Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49f63c0f0d | ||
|
|
33910aedb8 | ||
|
|
3359a81a14 | ||
|
|
e27f850e68 | ||
|
|
07340b8f53 | ||
|
|
2f9dd7faa8 | ||
|
|
3f81fd4a87 | ||
|
|
4dd961fc66 | ||
|
|
0bd70bfb32 | ||
|
|
3ab845d2d6 | ||
|
|
443f09d5a2 | ||
|
|
3500952bb7 | ||
|
|
e98182c4b5 | ||
|
|
2337827744 | ||
|
|
556dd66af3 | ||
|
|
8bdad3f4f9 | ||
|
|
6346d4143d | ||
|
|
fd8dc88760 | ||
|
|
b2810f390e | ||
|
|
23d3cd0f4b | ||
|
|
4a3c76773d | ||
|
|
d23e7604f0 | ||
|
|
0b3f6c6eff | ||
|
|
f2869c892b | ||
|
|
3755a9529b | ||
|
|
890f0593ee | ||
|
|
e6d666b5b0 | ||
|
|
f440acf145 | ||
|
|
1ad0e0c6dd | ||
|
|
bb8691ddc0 | ||
|
|
cf3041d07b | ||
|
|
313b3d5d6b | ||
|
|
122e7336be | ||
|
|
e954453f6b | ||
|
|
55ef3d09f3 | ||
|
|
88b9cc5ac9 | ||
|
|
f07cb7470d | ||
|
|
bd874a0232 | ||
|
|
7cc4cccb9c | ||
|
|
e85a3bacb7 | ||
|
|
530dfa758f | ||
|
|
8bc3489060 | ||
|
|
6914cb171a | ||
|
|
176c2bbd4c | ||
|
|
7771954455 | ||
|
|
a66743bb20 | ||
|
|
851c7b75f9 | ||
|
|
ed0b406027 | ||
|
|
71985972a2 | ||
|
|
2dbeef9290 | ||
|
|
a79453270d | ||
|
|
ae71808c61 | ||
|
|
5c195ba37b | ||
|
|
607ee17a86 | ||
|
|
a15aacc5b3 |
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
Dockerfile
|
||||
src/core/engines/gows/grpc
|
||||
src/core/engines/gows/proto
|
||||
.*sessions
|
||||
sessions
|
||||
files
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
src/core/engines/gows/grpc/*
|
||||
src/core/engines/gows/proto/*
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
src/core/engines/gows/grpc
|
||||
src/core/engines/gows/proto
|
||||
.env
|
||||
*.heapsnapshot
|
||||
.yarn
|
||||
|
||||
@@ -3,6 +3,7 @@ exclude: |
|
||||
^src/dashboard/.*|
|
||||
^src/core/engines/webjs/.*html|
|
||||
^src/core/engines/gows/grpc/.*|
|
||||
^src/core/engines/gows/proto/.*|
|
||||
^src/plus/engines/webjs/.*html|
|
||||
^.yarn/.*
|
||||
)$
|
||||
@@ -74,4 +75,6 @@ repos:
|
||||
.pre-commit-config.yaml|
|
||||
^src/core/engines/webjs/session.webjs.core.ts|
|
||||
^src/core/engines/webjs/_lodash.js|
|
||||
^tests/perf/.*|
|
||||
^scripts/.*|
|
||||
)$
|
||||
+26
-37
@@ -1,9 +1,3 @@
|
||||
# GOWS
|
||||
ARG GOWS_GITHUB_REPO=devlikeapro/gows
|
||||
ARG GOWS_SHA=39ba4dcceeeb6e6fab172ee71ad1c09deea4db16
|
||||
ARG WAHA_DASHBOARD_GITHUB_REPO=devlikeapro/dashboard
|
||||
ARG WAHA_DASHBOARD_SHA=a1c839d8da94d1cade182addffdfc42fc0cf7ed3
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
@@ -11,12 +5,8 @@ ARG NODE_VERSION=22.8-bullseye
|
||||
FROM node:${NODE_VERSION} AS build
|
||||
ENV PUPPETEER_SKIP_DOWNLOAD=True
|
||||
|
||||
# install protoc
|
||||
RUN apt-get update && \
|
||||
apt-get install protobuf-compiler -y
|
||||
|
||||
# npm packages
|
||||
WORKDIR /src
|
||||
WORKDIR /git
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
ENV YARN_CHECKSUM_BEHAVIOR=update
|
||||
@@ -25,19 +15,9 @@ RUN yarn set version 3.6.3
|
||||
RUN yarn install
|
||||
|
||||
# App
|
||||
WORKDIR /src
|
||||
ADD . /src
|
||||
WORKDIR /git
|
||||
ADD . /git
|
||||
RUN yarn install
|
||||
|
||||
# Build node grpc client for GOWS engine
|
||||
WORKDIR /gows/proto
|
||||
ARG GOWS_GITHUB_REPO
|
||||
ARG GOWS_SHA
|
||||
RUN wget https://raw.githubusercontent.com/${GOWS_GITHUB_REPO}/${GOWS_SHA}/proto/gows.proto
|
||||
WORKDIR /src
|
||||
|
||||
RUN make proto-gows
|
||||
|
||||
RUN yarn build && find ./dist -name "*.d.ts" -delete
|
||||
|
||||
#
|
||||
@@ -45,10 +25,13 @@ RUN yarn build && find ./dist -name "*.d.ts" -delete
|
||||
#
|
||||
FROM node:${NODE_VERSION} AS dashboard
|
||||
|
||||
# Download WAHA Dashboard
|
||||
ARG WAHA_DASHBOARD_GITHUB_REPO
|
||||
ARG WAHA_DASHBOARD_SHA
|
||||
# jq to parse json
|
||||
RUN apt-get update && apt-get install -y jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY waha.config.json /tmp/waha.config.json
|
||||
RUN \
|
||||
WAHA_DASHBOARD_GITHUB_REPO=$(jq -r '.waha.dashboard.repo' /tmp/waha.config.json) && \
|
||||
WAHA_DASHBOARD_SHA=$(jq -r '.waha.dashboard.ref' /tmp/waha.config.json) && \
|
||||
wget https://github.com/${WAHA_DASHBOARD_GITHUB_REPO}/archive/${WAHA_DASHBOARD_SHA}.zip \
|
||||
&& unzip ${WAHA_DASHBOARD_SHA}.zip -d /tmp/dashboard \
|
||||
&& mkdir -p /dashboard \
|
||||
@@ -60,6 +43,10 @@ RUN \
|
||||
# GOWS
|
||||
#
|
||||
FROM golang:1.23-bullseye AS gows
|
||||
|
||||
# jq to parse json
|
||||
RUN apt-get update && apt-get install -y jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# install protoc
|
||||
RUN apt-get update && \
|
||||
apt-get install protobuf-compiler -y
|
||||
@@ -69,16 +56,18 @@ RUN apt-get update \
|
||||
&& apt-get install -y libvips-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ARG GOWS_GITHUB_REPO
|
||||
ARG GOWS_SHA
|
||||
RUN git clone https://github.com/${GOWS_GITHUB_REPO} gows && \
|
||||
cd gows && \
|
||||
git checkout ${GOWS_SHA}
|
||||
|
||||
COPY waha.config.json /tmp/waha.config.json
|
||||
WORKDIR /go/gows
|
||||
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||
RUN make all
|
||||
RUN \
|
||||
GOWS_GITHUB_REPO=$(jq -r '.waha.gows.repo' /tmp/waha.config.json) && \
|
||||
GOWS_SHA=$(jq -r '.waha.gows.ref' /tmp/waha.config.json) && \
|
||||
ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"; \
|
||||
elif [ "$ARCH" = "aarch64" ]; then ARCH="arm64"; \
|
||||
else echo "Unsupported architecture: $ARCH" && exit 1; fi && \
|
||||
mkdir -p /go/gows/bin && \
|
||||
wget -O /go/gows/bin/gows https://github.com/${GOWS_GITHUB_REPO}/releases/download/v.${GOWS_SHA}/gows-${ARCH} && \
|
||||
chmod +x /go/gows/bin/gows
|
||||
|
||||
|
||||
#
|
||||
@@ -163,8 +152,8 @@ ENV WHATSAPP_DEFAULT_ENGINE=$WHATSAPP_DEFAULT_ENGINE
|
||||
# Attach sources, install packages
|
||||
WORKDIR /app
|
||||
COPY package.json ./
|
||||
COPY --from=build /src/node_modules ./node_modules
|
||||
COPY --from=build /src/dist ./dist
|
||||
COPY --from=build /git/node_modules ./node_modules
|
||||
COPY --from=build /git/dist ./dist
|
||||
COPY --from=dashboard /dashboard ./dist/dashboard
|
||||
COPY --from=gows /go/gows/bin/gows /app/gows
|
||||
ENV WAHA_GOWS_PATH /app/gows
|
||||
|
||||
@@ -35,7 +35,7 @@ for-swagger:
|
||||
WHATSAPP_SWAGGER_CONFIG_ADVANCED=true . ${NVM_DIR}/nvm.sh && nvm exec yarn start
|
||||
|
||||
up-noweb:
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-678
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-6712
|
||||
|
||||
up-noweb-libsignal:
|
||||
. ${NVM_DIR}/nvm.sh && nvm exec yarn up libsignal@github:devlikeapro/libsignal-node#fork-master
|
||||
@@ -47,15 +47,7 @@ start-proxy:
|
||||
docker run --rm -d --name squid-container -e TZ=UTC -p 3128:3128 ubuntu/squid:5.2-22.04_beta
|
||||
|
||||
proto-gows:
|
||||
rm -rf src/core/engines/gows/grpc
|
||||
mkdir -p src/core/engines/gows/grpc
|
||||
protoc \
|
||||
--plugin=protoc-gen-ts=node_modules/.bin/protoc-gen-ts \
|
||||
--plugin=protoc-gen-grpc=node_modules/.bin/grpc_tools_node_protoc_plugin \
|
||||
--js_out=import_style=commonjs,binary:src/core/engines/gows/grpc \
|
||||
--grpc_out=grpc_js:src/core/engines/gows/grpc \
|
||||
--ts_out=grpc_js:src/core/engines/gows/grpc \
|
||||
-I ../gows/proto ../gows/proto/gows.proto
|
||||
node scripts/gows-proto.js build --dir ../gows/proto
|
||||
|
||||
gows:
|
||||
cd ../gows && \
|
||||
|
||||
@@ -6,22 +6,16 @@
|
||||
|
||||
**WAHA** - **W**hats**A**pp **H**TTP **A**PI (REST API) that you can install on your own server and run in less than 5 minutes!
|
||||
|
||||
[](https://hub.docker.com/r/devlikeapro/waha)
|
||||
[](https://hub.docker.com/r/devlikeapro/waha)
|
||||
|
||||
- Documentation: [https://waha.devlike.pro/](https://waha.devlike.pro/)
|
||||
- Dashboard Example: [https://waha.devlike.pro/dashboard](https://waha.devlike.pro/dashboard)
|
||||
- Swagger Example: [https://waha.devlike.pro/swagger](https://waha.devlike.pro/swagger)
|
||||
|
||||
# Tables of Contents
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
- [Features](#features)
|
||||
* [Messages](#messages)
|
||||
* [Sessions](#sessions)
|
||||
* [Security](#security)
|
||||
* [Updates](#updates)
|
||||
* [Groups](#groups)
|
||||
* [Contacts](#contacts)
|
||||
- [Quick start](#quick-start)
|
||||
* [Requirements](#requirements)
|
||||
* [Send your first message](#send-your-first-message)
|
||||
@@ -32,52 +26,11 @@
|
||||
+ [5. Get the screenshot](#5-get-the-screenshot)
|
||||
+ [6. Send a text message](#6-send-a-text-message)
|
||||
* [What is next?](#what-is-next)
|
||||
- [Development](#development)
|
||||
* [Start the project](#start-the-project)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
# Features
|
||||
|
||||
## Messages
|
||||
- Send messages
|
||||
- Receive messages
|
||||
- Message replies
|
||||
- Send location
|
||||
- Receive location
|
||||
- React to messages
|
||||
- Send media (images/documents/files)
|
||||
- Send voice messages
|
||||
- Receive media (images/audio/video/documents)
|
||||
- Receive messages - webhook retries
|
||||
|
||||
## Sessions
|
||||
- Multi Device
|
||||
- Get the screenshot
|
||||
- Session saving (don't have to scan QR on every restart)
|
||||
- Single WhatsApp account running inside one container
|
||||
- Multiple WhatsApp account running inside one container
|
||||
|
||||
## Security
|
||||
- Swagger panel authentication
|
||||
- API authentication
|
||||
|
||||
## Updates
|
||||
- Bug fixes and updates come as soon as they are implemented.
|
||||
|
||||
## Groups
|
||||
- Create a group
|
||||
- Get invite for group
|
||||
- Modify group info (subject, description)
|
||||
- Add group participants
|
||||
- Kick group participants
|
||||
- Promote/demote group participants
|
||||
|
||||
## Contacts
|
||||
- Mute/unmute chats
|
||||
- Block/unblock contacts
|
||||
- Get contact info
|
||||
- Get profile pictures
|
||||
- Get presence (online\offline\typing) status
|
||||
|
||||
# Quick start
|
||||
|
||||
## Requirements
|
||||
@@ -87,13 +40,6 @@ instruction <a href="https://docs.docker.com/get-docker/" target="_blank" rel="n
|
||||
|
||||
When you are ready - come back and follows the below steps to send the first text message to WhatsApp via HTTP API!
|
||||
|
||||
{{< details "Why Docker?" >}}
|
||||
Docker makes it easy to ship all-in-one solution with the runtime and dependencies. You don't have to worry about
|
||||
language-specific libraries or chrome installation.
|
||||
|
||||
Also Docker makes installation and update processes so simple, just one command!
|
||||
{{< /details >}}
|
||||
|
||||
## Send your first message
|
||||
|
||||
Let's go over steps that allow you to send your first text message via WhatsApp HTTP API!
|
||||
@@ -114,7 +60,7 @@ docker pull devlikeapro/waha-plus
|
||||
docker logout
|
||||
```
|
||||
|
||||
Read more about how to get `PASSWORD` for [Plus Version →]({{< relref "plus-version" >}})
|
||||
Read more about how to get `PASSWORD` for [**➕ WAHA Plus**](https://waha.devlike.pro/docs/how-to/waha-plus/)
|
||||
|
||||
### 2. Run WhatsApp HTTP API
|
||||
|
||||
@@ -195,3 +141,19 @@ curl -d "{\"chatId\": \"${PHONE}@c.us\", \"text\": \"Hello from WhatsApp HTTP AP
|
||||
|
||||
## What is next?
|
||||
[Go and read the full documentation!](https://waha.devlike.pro/docs/overview/introduction/)
|
||||
|
||||
# Development
|
||||
|
||||
## Start the project
|
||||
1. Clone the repository
|
||||
2. Make sure you're using node>=22
|
||||
3. Run the following commands:
|
||||
```bash
|
||||
# Install dependencies
|
||||
yarn install
|
||||
# Fetch and compile proto files
|
||||
yarn gows:proto
|
||||
# Run
|
||||
yarn start
|
||||
# open http://localhost:3000
|
||||
```
|
||||
+1
-1
@@ -38,7 +38,7 @@ services:
|
||||
# command:
|
||||
# - postgres
|
||||
# - "-c"
|
||||
# - "max_connections=1000"
|
||||
# - "max_connections=3000"
|
||||
|
||||
# NOTE: Only if you're using MongoDB
|
||||
# https://waha.devlike.pro/docs/how-to/storages/#sessions---mongodb
|
||||
|
||||
+7
-3
@@ -20,10 +20,13 @@
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"gows:proto:fetch": "node scripts/gows-proto.js fetch",
|
||||
"gows:proto:build": "node scripts/gows-proto.js build",
|
||||
"gows:proto": "yarn gows:proto:fetch && yarn gows:proto:build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-678",
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-6712",
|
||||
"@adiwajshing/keyed-db": "^0.2.4",
|
||||
"@aws-sdk/client-s3": "^3.633.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.633.0",
|
||||
@@ -120,7 +123,8 @@
|
||||
"ts-loader": "^6.2.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.1.0",
|
||||
"typescript": "^4.8.4"
|
||||
"typescript": "^4.8.4",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const axios = require('axios');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { execSync } = require('child_process');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const yargs = require('yargs');
|
||||
|
||||
// Defaults
|
||||
const CONFIG_FILE = 'waha.config.json';
|
||||
// Load defaults from package.json
|
||||
gows = (() => {
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
||||
return config.waha.gows || {};
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
})();
|
||||
|
||||
const DEFAULT_REPO = gows.repo;
|
||||
if (!DEFAULT_REPO) {
|
||||
throw new Error(`Missing default repo in ${CONFIG_FILE}`);
|
||||
}
|
||||
const DEFAULT_REF = gows.ref;
|
||||
if (!DEFAULT_REF) {
|
||||
throw new Error('Missing default ref in ${CONFIG_FILE}');
|
||||
}
|
||||
const DEFAULT_DIR = './src/core/engines/gows/proto';
|
||||
|
||||
const PROTO_FILES = ['gows.proto'];
|
||||
const PROTO_OUTPUT = './src/core/engines/gows/grpc';
|
||||
|
||||
// Helper function to clean directory
|
||||
function cleanDirectory(directory, suffix) {
|
||||
if (!fs.existsSync(directory)) {
|
||||
fs.mkdirSync(directory, { recursive: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(directory);
|
||||
for (const file of files) {
|
||||
const filePath = path.join(directory, file);
|
||||
if (file.endsWith(suffix)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to download files
|
||||
async function downloadFiles(repo, ref, directory) {
|
||||
for (const file of PROTO_FILES) {
|
||||
const url = `https://github.com/${repo}/releases/download/v.${ref}/${file}`;
|
||||
const filePath = path.join(directory, file);
|
||||
try {
|
||||
const response = await axios.get(url, { responseType: 'arraybuffer' });
|
||||
fs.writeFileSync(filePath, response.data);
|
||||
console.log(`Downloaded: ${file}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to download ${file}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for fetch command
|
||||
async function handleFetch(repo, ref, dir) {
|
||||
console.log(`Fetching .proto files from ${repo}@${ref} to ${dir}...`);
|
||||
cleanDirectory(dir, '.proto');
|
||||
await downloadFiles(repo, ref, dir);
|
||||
}
|
||||
|
||||
// Handler for build command
|
||||
function handleBuild(dir) {
|
||||
console.log('Building gRPC files...');
|
||||
cleanDirectory(PROTO_OUTPUT);
|
||||
|
||||
const command = `grpc_tools_node_protoc \
|
||||
--plugin=protoc-gen-ts=node_modules/.bin/protoc-gen-ts \
|
||||
--plugin=protoc-gen-grpc=node_modules/.bin/grpc_tools_node_protoc_plugin \
|
||||
--js_out=import_style=commonjs,binary:${PROTO_OUTPUT} \
|
||||
--grpc_out=grpc_js:${PROTO_OUTPUT} \
|
||||
--ts_out=grpc_js:${PROTO_OUTPUT} \
|
||||
-I ${dir} ${dir}/gows.proto`;
|
||||
|
||||
try {
|
||||
execSync(command, { stdio: 'inherit' });
|
||||
console.log('gRPC files built successfully.');
|
||||
} catch (error) {
|
||||
console.error(`Failed to build gRPC files: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Commands
|
||||
//
|
||||
|
||||
// fetch
|
||||
yargs.command(
|
||||
'fetch',
|
||||
'Fetch .proto files from GitHub',
|
||||
(yargs) => {
|
||||
yargs
|
||||
.option('repo', {
|
||||
describe: 'GitHub repository (owner/repo)',
|
||||
type: 'string',
|
||||
default: DEFAULT_REPO,
|
||||
})
|
||||
.option('ref', {
|
||||
describe: 'Git reference (branch or commit SHA)',
|
||||
type: 'string',
|
||||
default: DEFAULT_REF,
|
||||
})
|
||||
.option('dir', {
|
||||
describe: 'Directory to output .proto files',
|
||||
type: 'string',
|
||||
default: DEFAULT_DIR,
|
||||
});
|
||||
},
|
||||
async (argv) => {
|
||||
await handleFetch(argv.repo, argv.ref, argv.dir);
|
||||
},
|
||||
);
|
||||
|
||||
// build
|
||||
yargs.command(
|
||||
'build',
|
||||
'Build gRPC files from .proto files',
|
||||
(yargs) => {
|
||||
yargs.option('dir', {
|
||||
describe: 'Directory containing .proto files',
|
||||
type: 'string',
|
||||
default: DEFAULT_DIR,
|
||||
});
|
||||
},
|
||||
(argv) => {
|
||||
handleBuild(argv.dir);
|
||||
},
|
||||
);
|
||||
|
||||
// Parse arguments
|
||||
yargs.parse();
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "Starting WAHA..."
|
||||
|
||||
docker run -d \
|
||||
--restart=always \
|
||||
--name waha \
|
||||
-p 3000:3000/tcp \
|
||||
-v ./.sessions:/app/.sessions \
|
||||
-v ./.media:/app/.media \
|
||||
--env WHATSAPP_API_KEY=321 \
|
||||
--env WAHA_DASHBOARD_USERNAME=waha \
|
||||
--env WAHA_DASHBOARD_PASSWORD=waha \
|
||||
--env WAHA_LOG_FORMAT=JSON \
|
||||
--env WAHA_LOG_LEVEL=info \
|
||||
--env WHATSAPP_DEFAULT_ENGINE=WEBJS \
|
||||
--env WAHA_PRINT_QR=False \
|
||||
--env WHATSAPP_FILES_LIFETIME=0 \
|
||||
--env WHATSAPP_FILES_FOLDER=/app/.media \
|
||||
devlikeapro/waha-plus:latest
|
||||
|
||||
echo "WAHA started."
|
||||
@@ -1,21 +0,0 @@
|
||||
set -e
|
||||
echo "Updating WAHA..."
|
||||
echo "Logging in to Docker..."
|
||||
docker login -u devlikeapro # -p {KEY} - you can hard code key here https://portal.devlike.pro/
|
||||
|
||||
echo "Pulling the latest image..."
|
||||
docker pull devlikeapro/waha-plus
|
||||
|
||||
echo "Logging out of Docker..."
|
||||
docker logout
|
||||
|
||||
# Just pull if you're using WAHA Core
|
||||
# docker pull devlikeapro/waha
|
||||
|
||||
echo "Stopping the current container..."
|
||||
docker stop waha || true
|
||||
echo "Removing the current container..."
|
||||
docker rm waha || true
|
||||
|
||||
echo "Running WAHA..."
|
||||
sh ./waha-run.sh
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
Query,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { ApiFileAcceptHeader } from '@waha/nestjs/ApiFileAcceptHeader';
|
||||
import {
|
||||
@@ -19,8 +18,6 @@ import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { WhatsappSession } from '../core/abc/session.abc';
|
||||
import { BufferResponseInterceptor } from '../nestjs/BufferResponseInterceptor';
|
||||
import {
|
||||
CaptchaBody,
|
||||
OTPRequest,
|
||||
QRCodeFormat,
|
||||
QRCodeQuery,
|
||||
QRCodeValue,
|
||||
@@ -63,42 +60,6 @@ class AuthController {
|
||||
) {
|
||||
return session.requestCode(request.phoneNumber, request.method, request);
|
||||
}
|
||||
|
||||
@Post('authorize-code')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary: 'Send OTP authentication code.',
|
||||
})
|
||||
authorizeCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Body() request: OTPRequest,
|
||||
) {
|
||||
return session.authorizeCode(request.code);
|
||||
}
|
||||
|
||||
@Get('captcha')
|
||||
@SessionApiParam
|
||||
@ApiFileAcceptHeader()
|
||||
@UseInterceptors(new BufferResponseInterceptor())
|
||||
@ApiOperation({
|
||||
summary: 'Get captcha image.',
|
||||
})
|
||||
async getCaptcha(@SessionParam session: WhatsappSession): Promise<Buffer> {
|
||||
const image = await session.getCaptcha();
|
||||
return image.get();
|
||||
}
|
||||
|
||||
@Post('captcha')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary: 'Enter captcha code.',
|
||||
})
|
||||
saveCaptcha(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Body() body: CaptchaBody,
|
||||
) {
|
||||
return session.saveCaptcha(body.code);
|
||||
}
|
||||
}
|
||||
|
||||
export { AuthController };
|
||||
@@ -3,31 +3,129 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
Query,
|
||||
UsePipes,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { ApiOperation, ApiParam, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { ChannelsInfoServiceCore } from '@waha/core/services/ChannelsInfoServiceCore';
|
||||
import {
|
||||
SessionApiParam,
|
||||
WorkingSessionParam,
|
||||
} from '@waha/nestjs/params/SessionApiParam';
|
||||
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
|
||||
import {
|
||||
Channel,
|
||||
ChannelCategory,
|
||||
ChannelCountry,
|
||||
ChannelListResult,
|
||||
ChannelMessage,
|
||||
ChannelSearchByText,
|
||||
ChannelSearchByView,
|
||||
ChannelView,
|
||||
CreateChannelRequest,
|
||||
ListChannelsQuery,
|
||||
NewsletterIdApiParam,
|
||||
NewsletterIdOrInviteCodeApiParam,
|
||||
PreviewChannelMessages,
|
||||
} from '@waha/structures/channels.dto';
|
||||
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { isNewsletter, WhatsappSession } from '../core/abc/session.abc';
|
||||
import {
|
||||
isNewsletter,
|
||||
parseChannelInviteLink,
|
||||
WhatsappSession,
|
||||
} from '../core/abc/session.abc';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/:session/channels')
|
||||
@ApiTags('📢 Channels')
|
||||
export class ChannelsController {
|
||||
constructor(private manager: SessionManager) {}
|
||||
constructor(
|
||||
private manager: SessionManager,
|
||||
private channelsInfoService: ChannelsInfoServiceCore,
|
||||
) {}
|
||||
|
||||
@Post('/search/by-view')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@SessionApiParam
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
@ApiOperation({ summary: 'Search for channels (by view)' })
|
||||
async searchByView(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Body() request: ChannelSearchByView,
|
||||
): Promise<ChannelListResult> {
|
||||
return session.searchChannelsByView(request);
|
||||
}
|
||||
|
||||
@Post('/search/by-text')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@SessionApiParam
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
@ApiOperation({ summary: 'Search for channels (by text)' })
|
||||
async searchByText(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Body() request: ChannelSearchByText,
|
||||
): Promise<ChannelListResult> {
|
||||
return session.searchChannelsByText(request);
|
||||
}
|
||||
|
||||
@Get('/search/views')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get list of views for channel search' })
|
||||
getSearchViews(): Promise<ChannelView[]> {
|
||||
return this.channelsInfoService.getViews();
|
||||
}
|
||||
|
||||
@Get('/search/countries')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get list of countries for channel search' })
|
||||
getSearchCountries(): Promise<ChannelCountry[]> {
|
||||
return this.channelsInfoService.getCountries();
|
||||
}
|
||||
|
||||
@Get('/search/categories')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get list of categories for channel search' })
|
||||
getSearchCategories(): Promise<ChannelCategory[]> {
|
||||
return this.channelsInfoService.getCategories();
|
||||
}
|
||||
|
||||
@Get(':id/messages/preview')
|
||||
@SessionApiParam
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
@ApiParam({
|
||||
name: 'id',
|
||||
description: 'Channel id or invite code',
|
||||
required: true,
|
||||
type: 'string',
|
||||
schema: {
|
||||
default: '0029Va4K0PZ5a245NkngBA2M',
|
||||
},
|
||||
})
|
||||
@ApiOperation({
|
||||
summary: 'Preview channel messages',
|
||||
description:
|
||||
'You can use either ' +
|
||||
'invite code (https://www.whatsapp.com/channel/123) or (123)' +
|
||||
'OR' +
|
||||
'Channel ID (123@newsletter).',
|
||||
})
|
||||
async previewChannelMessages(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Param('id') code: string,
|
||||
@Query() query: PreviewChannelMessages,
|
||||
): Promise<ChannelMessage[]> {
|
||||
if (isNewsletter(code)) {
|
||||
const channel = await session.channelsGetChannel(code);
|
||||
code = parseChannelInviteLink(channel.invite);
|
||||
}
|
||||
const inviteCode = parseChannelInviteLink(code);
|
||||
return session.previewChannelMessages(inviteCode, query);
|
||||
}
|
||||
|
||||
@Get('')
|
||||
@SessionApiParam
|
||||
@@ -76,8 +174,7 @@ export class ChannelsController {
|
||||
if (isNewsletter(id)) {
|
||||
return session.channelsGetChannel(id);
|
||||
} else {
|
||||
// https://www.whatsapp.com/channel/123 => 123
|
||||
const inviteCode = id.split('/').pop();
|
||||
const inviteCode = parseChannelInviteLink(id);
|
||||
return session.channelsGetChannelByInviteCode(inviteCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '@waha/nestjs/params/SessionApiParam';
|
||||
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { WhatsappSession } from '../core/abc/session.abc';
|
||||
import { parseGroupInviteLink, WhatsappSession } from '../core/abc/session.abc';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
DescriptionRequest,
|
||||
@@ -53,8 +53,7 @@ export class GroupsController {
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Query() query: JoinGroupRequest,
|
||||
): Promise<any> {
|
||||
// https://chat.whatsapp.com/123 => 123
|
||||
const code = query.code.split('/').pop();
|
||||
const code = parseGroupInviteLink(query.code);
|
||||
return session.joinInfoGroup(code);
|
||||
}
|
||||
|
||||
@@ -65,8 +64,7 @@ export class GroupsController {
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Body() request: JoinGroupRequest,
|
||||
): Promise<JoinGroupResponse> {
|
||||
// https://chat.whatsapp.com/123 => 123
|
||||
const code = request.code.split('/').pop();
|
||||
const code = parseGroupInviteLink(request.code);
|
||||
const id = await session.joinGroup(code);
|
||||
return { id: id };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Put,
|
||||
UnprocessableEntityException,
|
||||
UsePipes,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { SessionManager } from '@waha/core/abc/manager.abc';
|
||||
import { WhatsappSession } from '@waha/core/abc/session.abc';
|
||||
import {
|
||||
SessionApiParam,
|
||||
WorkingSessionParam,
|
||||
} from '@waha/nestjs/params/SessionApiParam';
|
||||
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
|
||||
import { Result } from '@waha/structures/base.dto';
|
||||
import {
|
||||
MyProfile,
|
||||
ProfileNameRequest,
|
||||
ProfilePictureRequest,
|
||||
ProfileStatusRequest,
|
||||
} from '@waha/structures/profile.dto';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/:session/profile')
|
||||
@ApiTags('🆔 Profile')
|
||||
export class ProfileController {
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get my profile' })
|
||||
async getMyProfile(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
): Promise<MyProfile> {
|
||||
const me = session.getSessionMeInfo();
|
||||
if (!me) {
|
||||
throw new UnprocessableEntityException('No profile found');
|
||||
}
|
||||
const picture = await session.getContactProfilePicture(me.id, false);
|
||||
return {
|
||||
id: me.id,
|
||||
name: me.pushName,
|
||||
picture: picture || null,
|
||||
};
|
||||
}
|
||||
|
||||
@Put('/name')
|
||||
@SessionApiParam
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
@ApiOperation({ summary: 'Set my profile name' })
|
||||
async setProfileName(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Body() request: ProfileNameRequest,
|
||||
): Promise<Result> {
|
||||
const success = await session.setProfileName(request.name);
|
||||
return { success: success ?? true };
|
||||
}
|
||||
|
||||
@Put('/status')
|
||||
@SessionApiParam
|
||||
@UsePipes(new WAHAValidationPipe())
|
||||
@ApiOperation({ summary: 'Set profile status (About)' })
|
||||
async setProfileStatus(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Body() request: ProfileStatusRequest,
|
||||
): Promise<Result> {
|
||||
const success = await session.setProfileStatus(request.status);
|
||||
return { success: success ?? true };
|
||||
}
|
||||
|
||||
@Put('/picture')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Set profile picture' })
|
||||
async setProfilePicture(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
@Body() request: ProfilePictureRequest,
|
||||
): Promise<Result> {
|
||||
const success = await session.updateProfilePicture(request.file);
|
||||
return { success: success ?? true };
|
||||
}
|
||||
|
||||
@Delete('/picture')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Delete profile picture' })
|
||||
async deleteProfilePicture(
|
||||
@WorkingSessionParam session: WhatsappSession,
|
||||
): Promise<Result> {
|
||||
const success = await session.updateProfilePicture(null);
|
||||
return { success: success || true };
|
||||
}
|
||||
}
|
||||
@@ -57,13 +57,11 @@ export class SwaggerConfiguratorCore {
|
||||
.setVersion(VERSION.version)
|
||||
.addTag('🖥️ Sessions', 'Control WhatsApp sessions (accounts)')
|
||||
.addTag('🔑 Auth', 'Authentication')
|
||||
.addTag('🆔 Profile', 'Your profile information')
|
||||
.addTag('🖼️ Screenshot', 'Get screenshot of WhatsApp and show QR code')
|
||||
.addTag('📤 Chatting', 'Chatting methods')
|
||||
.addTag('📢 Channels', 'Channels (newsletters) methods')
|
||||
.addTag(
|
||||
'🟢 Status',
|
||||
'Status (aka stories) methods. <b>NOWEB</b> engine only!',
|
||||
)
|
||||
.addTag('🟢 Status', 'Status (aka stories) methods')
|
||||
.addTag('💬 Chats', `Chats methods`)
|
||||
.addTag(
|
||||
'👤 Contacts',
|
||||
@@ -140,6 +138,7 @@ export class SwaggerConfiguratorCore {
|
||||
webhooks[event] = {
|
||||
post: {
|
||||
summary: eventMetadata.description,
|
||||
deprecated: eventMetadata.deprecated || false,
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
|
||||
+100
-8
@@ -1,7 +1,12 @@
|
||||
import {
|
||||
Channel,
|
||||
ChannelListResult,
|
||||
ChannelMessage,
|
||||
ChannelSearchByText,
|
||||
ChannelSearchByView,
|
||||
CreateChannelRequest,
|
||||
ListChannelsQuery,
|
||||
PreviewChannelMessages,
|
||||
} from '@waha/structures/channels.dto';
|
||||
import {
|
||||
ChatSummary,
|
||||
@@ -10,6 +15,7 @@ import {
|
||||
GetChatMessagesQuery,
|
||||
} from '@waha/structures/chats.dto';
|
||||
import { SendButtonsRequest } from '@waha/structures/chatting.buttons.dto';
|
||||
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
|
||||
import { Label, LabelDTO, LabelID } from '@waha/structures/labels.dto';
|
||||
import { PaginationParams } from '@waha/structures/pagination.dto';
|
||||
import { WAMessage } from '@waha/structures/responses.dto';
|
||||
@@ -326,21 +332,58 @@ export abstract class WhatsappSession {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public authorizeCode(code: string) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
abstract getScreenshot(): Promise<Buffer>;
|
||||
|
||||
public getSessionMeInfo(): MeInfo | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
public getCaptcha(): Promise<QR> {
|
||||
/**
|
||||
* Profile methods
|
||||
*/
|
||||
public setProfileName(name: string): Promise<boolean> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public saveCaptcha(code: string) {
|
||||
public setProfileStatus(status: string): Promise<boolean> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async updateProfilePicture(
|
||||
file: BinaryFile | RemoteFile | null,
|
||||
): Promise<boolean> {
|
||||
if (file) {
|
||||
await this.setProfilePicture(file);
|
||||
} else {
|
||||
await this.deleteProfilePicture();
|
||||
}
|
||||
|
||||
// Refresh profile picture after update
|
||||
setTimeout(() => {
|
||||
this.logger.info('Refreshing my profile picture after update...');
|
||||
this.refreshMyProfilePicture()
|
||||
.then(() => {
|
||||
this.logger.info('Refreshed my profile picture after update');
|
||||
})
|
||||
.catch((err) => {
|
||||
this.logger.error('Error refreshing my profile picture after update');
|
||||
this.logger.error(err, err.stack);
|
||||
});
|
||||
}, 3_000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async refreshMyProfilePicture() {
|
||||
const me = this.getSessionMeInfo();
|
||||
await this.getContactProfilePicture(me.id, true);
|
||||
}
|
||||
|
||||
protected setProfilePicture(file: BinaryFile | RemoteFile): Promise<boolean> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
protected deleteProfilePicture(): Promise<boolean> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
@@ -515,7 +558,7 @@ export abstract class WhatsappSession {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContactAbout(query: ContactQuery) {
|
||||
public getContactAbout(query: ContactQuery): Promise<{ about: string }> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
@@ -537,8 +580,16 @@ export abstract class WhatsappSession {
|
||||
}
|
||||
|
||||
protected async refreshProfilePicture(id: string) {
|
||||
let fn: Promise<string>;
|
||||
if (isNewsletter(id)) {
|
||||
fn = this.channelsGetChannel(id).then(
|
||||
(channel: Channel) => channel.picture || channel.preview,
|
||||
);
|
||||
} else {
|
||||
fn = this.fetchContactProfilePicture(id);
|
||||
}
|
||||
this.profilePictures.del(id);
|
||||
const url = await this.fetchContactProfilePicture(id).catch((err) => {
|
||||
const url = await fn.catch((err) => {
|
||||
this.logger.warn('Error fetching profile picture');
|
||||
this.logger.warn(err, err.stack);
|
||||
return null;
|
||||
@@ -661,6 +712,25 @@ export abstract class WhatsappSession {
|
||||
/**
|
||||
* Channels methods
|
||||
*/
|
||||
public searchChannelsByView(
|
||||
query: ChannelSearchByView,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public searchChannelsByText(
|
||||
query: ChannelSearchByText,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async previewChannelMessages(
|
||||
inviteCode: string,
|
||||
query: PreviewChannelMessages,
|
||||
): Promise<ChannelMessage[]> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public channelsList(query: ListChannelsQuery): Promise<Channel[]> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
@@ -769,6 +839,28 @@ export function isNewsletter(jid: string) {
|
||||
return jid.endsWith('@newsletter');
|
||||
}
|
||||
|
||||
export function getGroupInviteLink(code: string) {
|
||||
if (code.startsWith('https://')) {
|
||||
return code;
|
||||
}
|
||||
return `https://chat.whatsapp.com/${code}`;
|
||||
}
|
||||
|
||||
export function parseGroupInviteLink(link: string) {
|
||||
// https://chat.whatsapp.com/123 => 123
|
||||
return link.split('/').pop();
|
||||
}
|
||||
|
||||
export function getChannelInviteLink(code: string) {
|
||||
return `https://whatsapp.com/channel/${code}`;
|
||||
}
|
||||
|
||||
export function parseChannelInviteLink(link: string): string {
|
||||
// https://www.whatsapp.com/channel/123 => 123
|
||||
const code = link.split('/').pop();
|
||||
return code;
|
||||
}
|
||||
|
||||
export function getPublicUrlFromDirectPath(directPath: string) {
|
||||
return `https://pps.whatsapp.net${directPath}`;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export class WebsocketGatewayCore
|
||||
OnGatewayDisconnect,
|
||||
BeforeApplicationShutdown
|
||||
{
|
||||
HEARTBEAT_INTERVAL = 10_000;
|
||||
HEARTBEAT_INTERVAL = 60_000;
|
||||
|
||||
@WebSocketServer()
|
||||
server: Server;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { PassportModule } from '@nestjs/passport';
|
||||
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||
import { TerminusModule } from '@nestjs/terminus';
|
||||
import { ChannelsController } from '@waha/api/channels.controller';
|
||||
import { ProfileController } from '@waha/api/profile.controller';
|
||||
import {
|
||||
ServerController,
|
||||
ServerDebugController,
|
||||
@@ -14,6 +15,7 @@ import { GowsEngineConfigService } from '@waha/core/config/GowsEngineConfigServi
|
||||
import { WebJSEngineConfigService } from '@waha/core/config/WebJSEngineConfigService';
|
||||
import { MediaLocalStorageModule } from '@waha/core/media/local/media.local.storage.module';
|
||||
import { MediaLocalStorageConfig } from '@waha/core/media/local/MediaLocalStorageConfig';
|
||||
import { ChannelsInfoServiceCore } from '@waha/core/services/ChannelsInfoServiceCore';
|
||||
import { BufferJsonReplacerInterceptor } from '@waha/nestjs/BufferJsonReplacerInterceptor';
|
||||
import {
|
||||
getPinoHttpUseLevel,
|
||||
@@ -120,6 +122,7 @@ const IMPORTS = [...IMPORTS_CORE, ...IMPORTS_MEDIA];
|
||||
export const CONTROLLERS = [
|
||||
AuthController,
|
||||
SessionsController,
|
||||
ProfileController,
|
||||
ChattingController,
|
||||
ChatsController,
|
||||
ChannelsController,
|
||||
@@ -148,6 +151,7 @@ const PROVIDERS = [
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: BufferJsonReplacerInterceptor,
|
||||
},
|
||||
ChannelsInfoServiceCore,
|
||||
DashboardConfigServiceCore,
|
||||
SwaggerConfigServiceCore,
|
||||
WebJSEngineConfigService,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum Jid {
|
||||
BROADCAST = 'status@broadcast',
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
import {
|
||||
GOWSGroupParticipant,
|
||||
GroupInfoEvent,
|
||||
GroupInfoFull,
|
||||
JoinedGroupEvent,
|
||||
} from '@waha/core/engines/gows/types.group';
|
||||
import { toJID } from '@waha/core/engines/noweb/session.noweb.core';
|
||||
import {
|
||||
GroupId,
|
||||
GroupInfo,
|
||||
GroupParticipant,
|
||||
GroupParticipantRole,
|
||||
} from '@waha/structures/groups.dto';
|
||||
import {
|
||||
GroupParticipantType,
|
||||
GroupV2JoinEvent,
|
||||
GroupV2LeaveEvent,
|
||||
GroupV2ParticipantsEvent,
|
||||
GroupV2UpdateEvent,
|
||||
} from '@waha/structures/groups.events.dto';
|
||||
import { MeInfo } from '@waha/structures/sessions.dto';
|
||||
|
||||
export function ToGroupV2JoinEvent(event: JoinedGroupEvent): GroupV2JoinEvent {
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
group: ToGroupInfo(event),
|
||||
_data: event,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2LeaveEvent(
|
||||
me: MeInfo | null,
|
||||
event: GroupInfoEvent,
|
||||
): GroupV2LeaveEvent | null {
|
||||
if (!event.Leave || event.Leave.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (!me?.id) {
|
||||
return null;
|
||||
}
|
||||
const jid = toJID(me.id);
|
||||
const left = event.Leave;
|
||||
if (!left.includes(jid)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
group: {
|
||||
id: event.JID,
|
||||
},
|
||||
_data: event,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2UpdateEvent(
|
||||
event: GroupInfoEvent,
|
||||
): GroupV2UpdateEvent | null {
|
||||
const group = ToGroupInfoPartial(event);
|
||||
if (!group) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
group: group,
|
||||
_data: event,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2ParticipantsEvents(
|
||||
event: GroupInfoEvent,
|
||||
): GroupV2ParticipantsEvent[] {
|
||||
const id: GroupId = {
|
||||
id: event.JID,
|
||||
};
|
||||
const events: GroupV2ParticipantsEvent[] = [];
|
||||
const maps = [
|
||||
{ participants: event.Leave, type: GroupParticipantType.LEAVE },
|
||||
{ participants: event.Join, type: GroupParticipantType.JOIN },
|
||||
{ participants: event.Promote, type: GroupParticipantType.PROMOTE },
|
||||
{ participants: event.Demote, type: GroupParticipantType.DEMOTE },
|
||||
];
|
||||
for (const map of maps) {
|
||||
const participants = getParticipants(map.participants, map.type);
|
||||
if (participants) {
|
||||
events.push({
|
||||
group: id,
|
||||
type: map.type,
|
||||
timestamp: Date.now(),
|
||||
participants: participants,
|
||||
_data: event,
|
||||
});
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
function getParticipants(jids: string[] | null, type: GroupParticipantType) {
|
||||
if (!jids) {
|
||||
return;
|
||||
}
|
||||
let role: GroupParticipantRole;
|
||||
switch (type) {
|
||||
case GroupParticipantType.JOIN:
|
||||
role = GroupParticipantRole.PARTICIPANT;
|
||||
break;
|
||||
case GroupParticipantType.LEAVE:
|
||||
role = GroupParticipantRole.LEFT;
|
||||
break;
|
||||
case GroupParticipantType.PROMOTE:
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
break;
|
||||
case GroupParticipantType.DEMOTE:
|
||||
role = GroupParticipantRole.PARTICIPANT;
|
||||
break;
|
||||
}
|
||||
const participants: GroupParticipant[] = [];
|
||||
for (const jid of jids) {
|
||||
participants.push({
|
||||
id: jid,
|
||||
role: role,
|
||||
});
|
||||
}
|
||||
return participants;
|
||||
}
|
||||
|
||||
function ToGroupInfo(group: GroupInfoFull): GroupInfo {
|
||||
const participants: GroupParticipant[] = extractParticipants(
|
||||
group.Participants,
|
||||
);
|
||||
return {
|
||||
id: group.JID,
|
||||
subject: group.Name,
|
||||
description: group.Topic,
|
||||
invite: undefined,
|
||||
participants: participants,
|
||||
membersCanAddNewMember: group.MemberAddMode === 'all_member_add',
|
||||
membersCanSendMessages: !!group.IsAnnounce,
|
||||
newMembersApprovalRequired: group.IsJoinApprovalRequired,
|
||||
};
|
||||
}
|
||||
|
||||
function ToGroupInfoPartial(group: GroupInfoEvent): GroupInfo | null {
|
||||
const announce: boolean | undefined = group.Announce?.IsAnnounce;
|
||||
let membersCanSendMessages: boolean | undefined;
|
||||
// revert announce or undefined
|
||||
if (announce === undefined) {
|
||||
membersCanSendMessages = undefined;
|
||||
} else {
|
||||
membersCanSendMessages = !announce;
|
||||
}
|
||||
|
||||
const info = {
|
||||
id: group.JID,
|
||||
subject: group.Name?.Name,
|
||||
description: group.Topic?.Topic,
|
||||
invite: group.NewInviteLink || undefined,
|
||||
membersCanAddNewMember: undefined,
|
||||
membersCanSendMessages: membersCanSendMessages,
|
||||
newMembersApprovalRequired:
|
||||
group.MembershipApprovalMode?.IsJoinApprovalRequired,
|
||||
participants: undefined,
|
||||
};
|
||||
// check if all fields are undefined but id - return null
|
||||
for (const key in info) {
|
||||
if (key !== 'id' && info[key] !== undefined) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractParticipants(
|
||||
participants: GOWSGroupParticipant[],
|
||||
): GroupParticipant[] {
|
||||
const result: GroupParticipant[] = [];
|
||||
for (const participant of participants) {
|
||||
let role: GroupParticipantRole;
|
||||
if (participant.IsSuperAdmin) {
|
||||
role = GroupParticipantRole.SUPERADMIN;
|
||||
} else if (participant.IsAdmin) {
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
} else {
|
||||
role = GroupParticipantRole.PARTICIPANT;
|
||||
}
|
||||
result.push({
|
||||
id: participant.JID,
|
||||
role: role,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,817 @@
|
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
'use strict';
|
||||
var grpc = require('@grpc/grpc-js');
|
||||
var gows_pb = require('./gows_pb.js');
|
||||
|
||||
function serialize_messages_ChatPresenceRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.ChatPresenceRequest)) {
|
||||
throw new Error('Expected argument of type messages.ChatPresenceRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_ChatPresenceRequest(buffer_arg) {
|
||||
return gows_pb.ChatPresenceRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_CheckPhonesRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.CheckPhonesRequest)) {
|
||||
throw new Error('Expected argument of type messages.CheckPhonesRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_CheckPhonesRequest(buffer_arg) {
|
||||
return gows_pb.CheckPhonesRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_CheckPhonesResponse(arg) {
|
||||
if (!(arg instanceof gows_pb.CheckPhonesResponse)) {
|
||||
throw new Error('Expected argument of type messages.CheckPhonesResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_CheckPhonesResponse(buffer_arg) {
|
||||
return gows_pb.CheckPhonesResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_CreateNewsletterRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.CreateNewsletterRequest)) {
|
||||
throw new Error('Expected argument of type messages.CreateNewsletterRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_CreateNewsletterRequest(buffer_arg) {
|
||||
return gows_pb.CreateNewsletterRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_DownloadMediaRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.DownloadMediaRequest)) {
|
||||
throw new Error('Expected argument of type messages.DownloadMediaRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_DownloadMediaRequest(buffer_arg) {
|
||||
return gows_pb.DownloadMediaRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_DownloadMediaResponse(arg) {
|
||||
if (!(arg instanceof gows_pb.DownloadMediaResponse)) {
|
||||
throw new Error('Expected argument of type messages.DownloadMediaResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_DownloadMediaResponse(buffer_arg) {
|
||||
return gows_pb.DownloadMediaResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_Empty(arg) {
|
||||
if (!(arg instanceof gows_pb.Empty)) {
|
||||
throw new Error('Expected argument of type messages.Empty');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_Empty(buffer_arg) {
|
||||
return gows_pb.Empty.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_EntityByIdRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.EntityByIdRequest)) {
|
||||
throw new Error('Expected argument of type messages.EntityByIdRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_EntityByIdRequest(buffer_arg) {
|
||||
return gows_pb.EntityByIdRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_EventJson(arg) {
|
||||
if (!(arg instanceof gows_pb.EventJson)) {
|
||||
throw new Error('Expected argument of type messages.EventJson');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_EventJson(buffer_arg) {
|
||||
return gows_pb.EventJson.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_GetChatsRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.GetChatsRequest)) {
|
||||
throw new Error('Expected argument of type messages.GetChatsRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_GetChatsRequest(buffer_arg) {
|
||||
return gows_pb.GetChatsRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_GetContactsRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.GetContactsRequest)) {
|
||||
throw new Error('Expected argument of type messages.GetContactsRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_GetContactsRequest(buffer_arg) {
|
||||
return gows_pb.GetContactsRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_GetMessagesRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.GetMessagesRequest)) {
|
||||
throw new Error('Expected argument of type messages.GetMessagesRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_GetMessagesRequest(buffer_arg) {
|
||||
return gows_pb.GetMessagesRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_GetNewsletterMessagesByInviteRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.GetNewsletterMessagesByInviteRequest)) {
|
||||
throw new Error('Expected argument of type messages.GetNewsletterMessagesByInviteRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_GetNewsletterMessagesByInviteRequest(buffer_arg) {
|
||||
return gows_pb.GetNewsletterMessagesByInviteRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_Json(arg) {
|
||||
if (!(arg instanceof gows_pb.Json)) {
|
||||
throw new Error('Expected argument of type messages.Json');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_Json(buffer_arg) {
|
||||
return gows_pb.Json.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_JsonList(arg) {
|
||||
if (!(arg instanceof gows_pb.JsonList)) {
|
||||
throw new Error('Expected argument of type messages.JsonList');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_JsonList(buffer_arg) {
|
||||
return gows_pb.JsonList.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_MarkReadRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.MarkReadRequest)) {
|
||||
throw new Error('Expected argument of type messages.MarkReadRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_MarkReadRequest(buffer_arg) {
|
||||
return gows_pb.MarkReadRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_MessageReaction(arg) {
|
||||
if (!(arg instanceof gows_pb.MessageReaction)) {
|
||||
throw new Error('Expected argument of type messages.MessageReaction');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_MessageReaction(buffer_arg) {
|
||||
return gows_pb.MessageReaction.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_MessageRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.MessageRequest)) {
|
||||
throw new Error('Expected argument of type messages.MessageRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_MessageRequest(buffer_arg) {
|
||||
return gows_pb.MessageRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_MessageResponse(arg) {
|
||||
if (!(arg instanceof gows_pb.MessageResponse)) {
|
||||
throw new Error('Expected argument of type messages.MessageResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_MessageResponse(buffer_arg) {
|
||||
return gows_pb.MessageResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_Newsletter(arg) {
|
||||
if (!(arg instanceof gows_pb.Newsletter)) {
|
||||
throw new Error('Expected argument of type messages.Newsletter');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_Newsletter(buffer_arg) {
|
||||
return gows_pb.Newsletter.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_NewsletterInfoRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.NewsletterInfoRequest)) {
|
||||
throw new Error('Expected argument of type messages.NewsletterInfoRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_NewsletterInfoRequest(buffer_arg) {
|
||||
return gows_pb.NewsletterInfoRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_NewsletterList(arg) {
|
||||
if (!(arg instanceof gows_pb.NewsletterList)) {
|
||||
throw new Error('Expected argument of type messages.NewsletterList');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_NewsletterList(buffer_arg) {
|
||||
return gows_pb.NewsletterList.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_NewsletterListRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.NewsletterListRequest)) {
|
||||
throw new Error('Expected argument of type messages.NewsletterListRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_NewsletterListRequest(buffer_arg) {
|
||||
return gows_pb.NewsletterListRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_NewsletterSearchPageResult(arg) {
|
||||
if (!(arg instanceof gows_pb.NewsletterSearchPageResult)) {
|
||||
throw new Error('Expected argument of type messages.NewsletterSearchPageResult');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_NewsletterSearchPageResult(buffer_arg) {
|
||||
return gows_pb.NewsletterSearchPageResult.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_NewsletterToggleFollowRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.NewsletterToggleFollowRequest)) {
|
||||
throw new Error('Expected argument of type messages.NewsletterToggleFollowRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_NewsletterToggleFollowRequest(buffer_arg) {
|
||||
return gows_pb.NewsletterToggleFollowRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_NewsletterToggleMuteRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.NewsletterToggleMuteRequest)) {
|
||||
throw new Error('Expected argument of type messages.NewsletterToggleMuteRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_NewsletterToggleMuteRequest(buffer_arg) {
|
||||
return gows_pb.NewsletterToggleMuteRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_PairCodeRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.PairCodeRequest)) {
|
||||
throw new Error('Expected argument of type messages.PairCodeRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_PairCodeRequest(buffer_arg) {
|
||||
return gows_pb.PairCodeRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_PairCodeResponse(arg) {
|
||||
if (!(arg instanceof gows_pb.PairCodeResponse)) {
|
||||
throw new Error('Expected argument of type messages.PairCodeResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_PairCodeResponse(buffer_arg) {
|
||||
return gows_pb.PairCodeResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_PresenceRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.PresenceRequest)) {
|
||||
throw new Error('Expected argument of type messages.PresenceRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_PresenceRequest(buffer_arg) {
|
||||
return gows_pb.PresenceRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_ProfileNameRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.ProfileNameRequest)) {
|
||||
throw new Error('Expected argument of type messages.ProfileNameRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_ProfileNameRequest(buffer_arg) {
|
||||
return gows_pb.ProfileNameRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_ProfilePictureRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.ProfilePictureRequest)) {
|
||||
throw new Error('Expected argument of type messages.ProfilePictureRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_ProfilePictureRequest(buffer_arg) {
|
||||
return gows_pb.ProfilePictureRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_ProfilePictureResponse(arg) {
|
||||
if (!(arg instanceof gows_pb.ProfilePictureResponse)) {
|
||||
throw new Error('Expected argument of type messages.ProfilePictureResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_ProfilePictureResponse(buffer_arg) {
|
||||
return gows_pb.ProfilePictureResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_ProfileStatusRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.ProfileStatusRequest)) {
|
||||
throw new Error('Expected argument of type messages.ProfileStatusRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_ProfileStatusRequest(buffer_arg) {
|
||||
return gows_pb.ProfileStatusRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_SearchNewslettersByTextRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.SearchNewslettersByTextRequest)) {
|
||||
throw new Error('Expected argument of type messages.SearchNewslettersByTextRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_SearchNewslettersByTextRequest(buffer_arg) {
|
||||
return gows_pb.SearchNewslettersByTextRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_SearchNewslettersByViewRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.SearchNewslettersByViewRequest)) {
|
||||
throw new Error('Expected argument of type messages.SearchNewslettersByViewRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_SearchNewslettersByViewRequest(buffer_arg) {
|
||||
return gows_pb.SearchNewslettersByViewRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_Session(arg) {
|
||||
if (!(arg instanceof gows_pb.Session)) {
|
||||
throw new Error('Expected argument of type messages.Session');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_Session(buffer_arg) {
|
||||
return gows_pb.Session.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_SessionStateResponse(arg) {
|
||||
if (!(arg instanceof gows_pb.SessionStateResponse)) {
|
||||
throw new Error('Expected argument of type messages.SessionStateResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_SessionStateResponse(buffer_arg) {
|
||||
return gows_pb.SessionStateResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_SetProfilePictureRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.SetProfilePictureRequest)) {
|
||||
throw new Error('Expected argument of type messages.SetProfilePictureRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_SetProfilePictureRequest(buffer_arg) {
|
||||
return gows_pb.SetProfilePictureRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_StartSessionRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.StartSessionRequest)) {
|
||||
throw new Error('Expected argument of type messages.StartSessionRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_StartSessionRequest(buffer_arg) {
|
||||
return gows_pb.StartSessionRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_messages_SubscribePresenceRequest(arg) {
|
||||
if (!(arg instanceof gows_pb.SubscribePresenceRequest)) {
|
||||
throw new Error('Expected argument of type messages.SubscribePresenceRequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_messages_SubscribePresenceRequest(buffer_arg) {
|
||||
return gows_pb.SubscribePresenceRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Events
|
||||
//
|
||||
var EventStreamService = exports.EventStreamService = {
|
||||
streamEvents: {
|
||||
path: '/messages.EventStream/StreamEvents',
|
||||
requestStream: false,
|
||||
responseStream: true,
|
||||
requestType: gows_pb.Session,
|
||||
responseType: gows_pb.EventJson,
|
||||
requestSerialize: serialize_messages_Session,
|
||||
requestDeserialize: deserialize_messages_Session,
|
||||
responseSerialize: serialize_messages_EventJson,
|
||||
responseDeserialize: deserialize_messages_EventJson,
|
||||
},
|
||||
};
|
||||
|
||||
exports.EventStreamClient = grpc.makeGenericClientConstructor(EventStreamService);
|
||||
var MessageServiceService = exports.MessageServiceService = {
|
||||
//
|
||||
// Session management
|
||||
//
|
||||
startSession: {
|
||||
path: '/messages.MessageService/StartSession',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.StartSessionRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_StartSessionRequest,
|
||||
requestDeserialize: deserialize_messages_StartSessionRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
stopSession: {
|
||||
path: '/messages.MessageService/StopSession',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.Session,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_Session,
|
||||
requestDeserialize: deserialize_messages_Session,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
getSessionState: {
|
||||
path: '/messages.MessageService/GetSessionState',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.Session,
|
||||
responseType: gows_pb.SessionStateResponse,
|
||||
requestSerialize: serialize_messages_Session,
|
||||
requestDeserialize: deserialize_messages_Session,
|
||||
responseSerialize: serialize_messages_SessionStateResponse,
|
||||
responseDeserialize: deserialize_messages_SessionStateResponse,
|
||||
},
|
||||
requestCode: {
|
||||
path: '/messages.MessageService/RequestCode',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.PairCodeRequest,
|
||||
responseType: gows_pb.PairCodeResponse,
|
||||
requestSerialize: serialize_messages_PairCodeRequest,
|
||||
requestDeserialize: deserialize_messages_PairCodeRequest,
|
||||
responseSerialize: serialize_messages_PairCodeResponse,
|
||||
responseDeserialize: deserialize_messages_PairCodeResponse,
|
||||
},
|
||||
logout: {
|
||||
path: '/messages.MessageService/Logout',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.Session,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_Session,
|
||||
requestDeserialize: deserialize_messages_Session,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
//
|
||||
// Profile
|
||||
//
|
||||
setProfileName: {
|
||||
path: '/messages.MessageService/SetProfileName',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.ProfileNameRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_ProfileNameRequest,
|
||||
requestDeserialize: deserialize_messages_ProfileNameRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
setProfileStatus: {
|
||||
path: '/messages.MessageService/SetProfileStatus',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.ProfileStatusRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_ProfileStatusRequest,
|
||||
requestDeserialize: deserialize_messages_ProfileStatusRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
setProfilePicture: {
|
||||
path: '/messages.MessageService/SetProfilePicture',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.SetProfilePictureRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_SetProfilePictureRequest,
|
||||
requestDeserialize: deserialize_messages_SetProfilePictureRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
//
|
||||
// Actions
|
||||
//
|
||||
sendMessage: {
|
||||
path: '/messages.MessageService/SendMessage',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.MessageRequest,
|
||||
responseType: gows_pb.MessageResponse,
|
||||
requestSerialize: serialize_messages_MessageRequest,
|
||||
requestDeserialize: deserialize_messages_MessageRequest,
|
||||
responseSerialize: serialize_messages_MessageResponse,
|
||||
responseDeserialize: deserialize_messages_MessageResponse,
|
||||
},
|
||||
sendReaction: {
|
||||
path: '/messages.MessageService/SendReaction',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.MessageReaction,
|
||||
responseType: gows_pb.MessageResponse,
|
||||
requestSerialize: serialize_messages_MessageReaction,
|
||||
requestDeserialize: deserialize_messages_MessageReaction,
|
||||
responseSerialize: serialize_messages_MessageResponse,
|
||||
responseDeserialize: deserialize_messages_MessageResponse,
|
||||
},
|
||||
getProfilePicture: {
|
||||
path: '/messages.MessageService/GetProfilePicture',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.ProfilePictureRequest,
|
||||
responseType: gows_pb.ProfilePictureResponse,
|
||||
requestSerialize: serialize_messages_ProfilePictureRequest,
|
||||
requestDeserialize: deserialize_messages_ProfilePictureRequest,
|
||||
responseSerialize: serialize_messages_ProfilePictureResponse,
|
||||
responseDeserialize: deserialize_messages_ProfilePictureResponse,
|
||||
},
|
||||
sendPresence: {
|
||||
path: '/messages.MessageService/SendPresence',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.PresenceRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_PresenceRequest,
|
||||
requestDeserialize: deserialize_messages_PresenceRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
sendChatPresence: {
|
||||
path: '/messages.MessageService/SendChatPresence',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.ChatPresenceRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_ChatPresenceRequest,
|
||||
requestDeserialize: deserialize_messages_ChatPresenceRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
subscribePresence: {
|
||||
path: '/messages.MessageService/SubscribePresence',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.SubscribePresenceRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_SubscribePresenceRequest,
|
||||
requestDeserialize: deserialize_messages_SubscribePresenceRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
markRead: {
|
||||
path: '/messages.MessageService/MarkRead',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.MarkReadRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_MarkReadRequest,
|
||||
requestDeserialize: deserialize_messages_MarkReadRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
checkPhones: {
|
||||
path: '/messages.MessageService/CheckPhones',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.CheckPhonesRequest,
|
||||
responseType: gows_pb.CheckPhonesResponse,
|
||||
requestSerialize: serialize_messages_CheckPhonesRequest,
|
||||
requestDeserialize: deserialize_messages_CheckPhonesRequest,
|
||||
responseSerialize: serialize_messages_CheckPhonesResponse,
|
||||
responseDeserialize: deserialize_messages_CheckPhonesResponse,
|
||||
},
|
||||
//
|
||||
// Newsletters
|
||||
//
|
||||
getSubscribedNewsletters: {
|
||||
path: '/messages.MessageService/GetSubscribedNewsletters',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.NewsletterListRequest,
|
||||
responseType: gows_pb.NewsletterList,
|
||||
requestSerialize: serialize_messages_NewsletterListRequest,
|
||||
requestDeserialize: deserialize_messages_NewsletterListRequest,
|
||||
responseSerialize: serialize_messages_NewsletterList,
|
||||
responseDeserialize: deserialize_messages_NewsletterList,
|
||||
},
|
||||
getNewsletterInfo: {
|
||||
path: '/messages.MessageService/GetNewsletterInfo',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.NewsletterInfoRequest,
|
||||
responseType: gows_pb.Newsletter,
|
||||
requestSerialize: serialize_messages_NewsletterInfoRequest,
|
||||
requestDeserialize: deserialize_messages_NewsletterInfoRequest,
|
||||
responseSerialize: serialize_messages_Newsletter,
|
||||
responseDeserialize: deserialize_messages_Newsletter,
|
||||
},
|
||||
getNewsletterMessagesByInvite: {
|
||||
path: '/messages.MessageService/GetNewsletterMessagesByInvite',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.GetNewsletterMessagesByInviteRequest,
|
||||
responseType: gows_pb.Json,
|
||||
requestSerialize: serialize_messages_GetNewsletterMessagesByInviteRequest,
|
||||
requestDeserialize: deserialize_messages_GetNewsletterMessagesByInviteRequest,
|
||||
responseSerialize: serialize_messages_Json,
|
||||
responseDeserialize: deserialize_messages_Json,
|
||||
},
|
||||
searchNewslettersByView: {
|
||||
path: '/messages.MessageService/SearchNewslettersByView',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.SearchNewslettersByViewRequest,
|
||||
responseType: gows_pb.NewsletterSearchPageResult,
|
||||
requestSerialize: serialize_messages_SearchNewslettersByViewRequest,
|
||||
requestDeserialize: deserialize_messages_SearchNewslettersByViewRequest,
|
||||
responseSerialize: serialize_messages_NewsletterSearchPageResult,
|
||||
responseDeserialize: deserialize_messages_NewsletterSearchPageResult,
|
||||
},
|
||||
searchNewslettersByText: {
|
||||
path: '/messages.MessageService/SearchNewslettersByText',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.SearchNewslettersByTextRequest,
|
||||
responseType: gows_pb.NewsletterSearchPageResult,
|
||||
requestSerialize: serialize_messages_SearchNewslettersByTextRequest,
|
||||
requestDeserialize: deserialize_messages_SearchNewslettersByTextRequest,
|
||||
responseSerialize: serialize_messages_NewsletterSearchPageResult,
|
||||
responseDeserialize: deserialize_messages_NewsletterSearchPageResult,
|
||||
},
|
||||
createNewsletter: {
|
||||
path: '/messages.MessageService/CreateNewsletter',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.CreateNewsletterRequest,
|
||||
responseType: gows_pb.Newsletter,
|
||||
requestSerialize: serialize_messages_CreateNewsletterRequest,
|
||||
requestDeserialize: deserialize_messages_CreateNewsletterRequest,
|
||||
responseSerialize: serialize_messages_Newsletter,
|
||||
responseDeserialize: deserialize_messages_Newsletter,
|
||||
},
|
||||
newsletterToggleMute: {
|
||||
path: '/messages.MessageService/NewsletterToggleMute',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.NewsletterToggleMuteRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_NewsletterToggleMuteRequest,
|
||||
requestDeserialize: deserialize_messages_NewsletterToggleMuteRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
newsletterToggleFollow: {
|
||||
path: '/messages.MessageService/NewsletterToggleFollow',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.NewsletterToggleFollowRequest,
|
||||
responseType: gows_pb.Empty,
|
||||
requestSerialize: serialize_messages_NewsletterToggleFollowRequest,
|
||||
requestDeserialize: deserialize_messages_NewsletterToggleFollowRequest,
|
||||
responseSerialize: serialize_messages_Empty,
|
||||
responseDeserialize: deserialize_messages_Empty,
|
||||
},
|
||||
//
|
||||
// Media
|
||||
//
|
||||
downloadMedia: {
|
||||
path: '/messages.MessageService/DownloadMedia',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.DownloadMediaRequest,
|
||||
responseType: gows_pb.DownloadMediaResponse,
|
||||
requestSerialize: serialize_messages_DownloadMediaRequest,
|
||||
requestDeserialize: deserialize_messages_DownloadMediaRequest,
|
||||
responseSerialize: serialize_messages_DownloadMediaResponse,
|
||||
responseDeserialize: deserialize_messages_DownloadMediaResponse,
|
||||
},
|
||||
//
|
||||
// Storage
|
||||
//
|
||||
getMessageById: {
|
||||
path: '/messages.MessageService/GetMessageById',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.EntityByIdRequest,
|
||||
responseType: gows_pb.Json,
|
||||
requestSerialize: serialize_messages_EntityByIdRequest,
|
||||
requestDeserialize: deserialize_messages_EntityByIdRequest,
|
||||
responseSerialize: serialize_messages_Json,
|
||||
responseDeserialize: deserialize_messages_Json,
|
||||
},
|
||||
getMessages: {
|
||||
path: '/messages.MessageService/GetMessages',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.GetMessagesRequest,
|
||||
responseType: gows_pb.JsonList,
|
||||
requestSerialize: serialize_messages_GetMessagesRequest,
|
||||
requestDeserialize: deserialize_messages_GetMessagesRequest,
|
||||
responseSerialize: serialize_messages_JsonList,
|
||||
responseDeserialize: deserialize_messages_JsonList,
|
||||
},
|
||||
getContacts: {
|
||||
path: '/messages.MessageService/GetContacts',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.GetContactsRequest,
|
||||
responseType: gows_pb.JsonList,
|
||||
requestSerialize: serialize_messages_GetContactsRequest,
|
||||
requestDeserialize: deserialize_messages_GetContactsRequest,
|
||||
responseSerialize: serialize_messages_JsonList,
|
||||
responseDeserialize: deserialize_messages_JsonList,
|
||||
},
|
||||
getContactById: {
|
||||
path: '/messages.MessageService/GetContactById',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.EntityByIdRequest,
|
||||
responseType: gows_pb.Json,
|
||||
requestSerialize: serialize_messages_EntityByIdRequest,
|
||||
requestDeserialize: deserialize_messages_EntityByIdRequest,
|
||||
responseSerialize: serialize_messages_Json,
|
||||
responseDeserialize: deserialize_messages_Json,
|
||||
},
|
||||
getChats: {
|
||||
path: '/messages.MessageService/GetChats',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: gows_pb.GetChatsRequest,
|
||||
responseType: gows_pb.JsonList,
|
||||
requestSerialize: serialize_messages_GetChatsRequest,
|
||||
requestDeserialize: deserialize_messages_GetChatsRequest,
|
||||
responseSerialize: serialize_messages_JsonList,
|
||||
responseDeserialize: deserialize_messages_JsonList,
|
||||
},
|
||||
};
|
||||
|
||||
exports.MessageServiceClient = grpc.makeGenericClientConstructor(MessageServiceService);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,42 @@
|
||||
import { messages } from '@waha/core/engines/gows/grpc/gows';
|
||||
import { MessageStatus } from '@waha/core/engines/gows/types';
|
||||
import { WAMessageAck } from '@waha/structures/enums.dto';
|
||||
|
||||
export function optional(value: any, type) {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
return new type({ value: value });
|
||||
}
|
||||
|
||||
export function parseJson(value: messages.Json | { data?: string }) {
|
||||
if (value instanceof messages.Json) {
|
||||
value = value.toObject();
|
||||
}
|
||||
if (value.data === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return JSON.parse(value.data);
|
||||
}
|
||||
|
||||
export function parseJsonList(value: messages.JsonList) {
|
||||
return value.toObject().elements.map((value) => parseJson(value));
|
||||
}
|
||||
|
||||
export function statusToAck(status: MessageStatus): WAMessageAck | null {
|
||||
switch (status) {
|
||||
case MessageStatus.Error:
|
||||
return WAMessageAck.ERROR;
|
||||
case MessageStatus.Pending:
|
||||
return WAMessageAck.PENDING;
|
||||
case MessageStatus.ServerAck:
|
||||
return WAMessageAck.SERVER;
|
||||
case MessageStatus.DeliveryAck:
|
||||
return WAMessageAck.DEVICE;
|
||||
case MessageStatus.Read:
|
||||
return WAMessageAck.READ;
|
||||
case MessageStatus.Played:
|
||||
return WAMessageAck.PLAYED;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1,8 +1,17 @@
|
||||
import { isJidGroup, jidNormalizedUser } from '@adiwajshing/baileys';
|
||||
import {
|
||||
getUrlFromDirectPath,
|
||||
isJidGroup,
|
||||
isJidStatusBroadcast,
|
||||
jidNormalizedUser,
|
||||
} from '@adiwajshing/baileys';
|
||||
import * as grpc from '@grpc/grpc-js';
|
||||
import { connectivityState } from '@grpc/grpc-js';
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
import { WhatsappSession } from '@waha/core/abc/session.abc';
|
||||
import {
|
||||
getChannelInviteLink,
|
||||
WhatsappSession,
|
||||
} from '@waha/core/abc/session.abc';
|
||||
import { Jid } from '@waha/core/engines/const';
|
||||
import { EventsFromObservable } from '@waha/core/engines/gows/EventsFromObservable';
|
||||
import { GowsEventStreamObservable } from '@waha/core/engines/gows/GowsEventStreamObservable';
|
||||
import { messages } from '@waha/core/engines/gows/grpc/gows';
|
||||
@@ -15,6 +24,17 @@ import {
|
||||
import { AvailableInPlusVersion } from '@waha/core/exceptions';
|
||||
import { IMediaEngineProcessor } from '@waha/core/media/IMediaEngineProcessor';
|
||||
import { QR } from '@waha/core/QR';
|
||||
import {
|
||||
Channel,
|
||||
ChannelListResult,
|
||||
ChannelMessage,
|
||||
ChannelRole,
|
||||
ChannelSearchByText,
|
||||
ChannelSearchByView,
|
||||
CreateChannelRequest,
|
||||
ListChannelsQuery,
|
||||
PreviewChannelMessages,
|
||||
} from '@waha/structures/channels.dto';
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
@@ -27,6 +47,7 @@ import {
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest,
|
||||
WANumberExistResult,
|
||||
} from '@waha/structures/chatting.dto';
|
||||
import {
|
||||
ACK_UNKNOWN,
|
||||
@@ -41,6 +62,7 @@ import {
|
||||
} from '@waha/structures/presence.dto';
|
||||
import { WAMessage, WAMessageReaction } from '@waha/structures/responses.dto';
|
||||
import { MeInfo, ProxyConfig } from '@waha/structures/sessions.dto';
|
||||
import { StatusRequest, TextStatus } from '@waha/structures/status.dto';
|
||||
import { EnginePayload, WAMessageAckBody } from '@waha/structures/webhooks.dto';
|
||||
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
|
||||
import { onlyEvent } from '@waha/utils/reactive/ops/onlyEvent';
|
||||
@@ -61,11 +83,35 @@ import { promisify } from 'util';
|
||||
|
||||
import * as gows from './types';
|
||||
import MessageServiceClient = messages.MessageServiceClient;
|
||||
import {
|
||||
ToGroupV2JoinEvent,
|
||||
ToGroupV2LeaveEvent,
|
||||
ToGroupV2ParticipantsEvents,
|
||||
ToGroupV2UpdateEvent,
|
||||
} from '@waha/core/engines/gows/groups.gows';
|
||||
import {
|
||||
optional,
|
||||
parseJson,
|
||||
parseJsonList,
|
||||
statusToAck,
|
||||
} from '@waha/core/engines/gows/helpers';
|
||||
import { extractMediaContent } from '@waha/core/engines/noweb/utils';
|
||||
import {
|
||||
ChatSortField,
|
||||
ChatSummary,
|
||||
GetChatMessageQuery,
|
||||
GetChatMessagesFilter,
|
||||
GetChatMessagesQuery,
|
||||
} from '@waha/structures/chats.dto';
|
||||
import { ContactQuery } from '@waha/structures/contacts.dto';
|
||||
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
|
||||
import { PaginationParams, SortOrder } from '@waha/structures/pagination.dto';
|
||||
|
||||
enum WhatsMeowEvent {
|
||||
CONNECTED = 'gows.ConnectedEventData',
|
||||
DISCONNECTED = 'events.Disconnected',
|
||||
KEEP_ALIVE_TIMEOUT = 'events.KeepAliveTimeout',
|
||||
KEEP_ALIVE_RESTORED = 'events.KeepAliveRestored',
|
||||
QR_CHANNEL_ITEM = 'whatsmeow.QRChannelItem',
|
||||
MESSAGE = 'events.Message',
|
||||
RECEIPT = 'events.Receipt',
|
||||
@@ -73,8 +119,16 @@ enum WhatsMeowEvent {
|
||||
CHAT_PRESENCE = 'events.ChatPresence',
|
||||
PUSH_NAME_SETTING = 'events.PushNameSetting',
|
||||
LOGGED_OUT = 'events.LoggedOut',
|
||||
// Groups
|
||||
GROUP_INFO = 'events.GroupInfo',
|
||||
JOINED_GROUP = 'events.JoinedGroup',
|
||||
}
|
||||
|
||||
const gRPCClientConfig = {
|
||||
'grpc.max_send_message_length': 128 * 1024 * 1024,
|
||||
'grpc.max_receive_message_length': 128 * 1024 * 1024,
|
||||
};
|
||||
|
||||
export interface GowsConfig {
|
||||
connection: string;
|
||||
}
|
||||
@@ -134,6 +188,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
this.client = new MessageServiceClient(
|
||||
this.engineConfig.connection,
|
||||
grpc.credentials.createInsecure(),
|
||||
gRPCClientConfig,
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -163,6 +218,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
const client = new messages.EventStreamClient(
|
||||
this.engineConfig.connection,
|
||||
grpc.credentials.createInsecure(),
|
||||
gRPCClientConfig,
|
||||
);
|
||||
const stream = client.StreamEvents(this.session);
|
||||
return { client, stream };
|
||||
@@ -195,6 +251,11 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
this.status = WAHASessionStatus.STARTING;
|
||||
}
|
||||
});
|
||||
events.on(WhatsMeowEvent.KEEP_ALIVE_RESTORED, () => {
|
||||
if (this.status != WAHASessionStatus.WORKING) {
|
||||
this.status = WAHASessionStatus.WORKING;
|
||||
}
|
||||
});
|
||||
events.on(WhatsMeowEvent.QR_CHANNEL_ITEM, async (data) => {
|
||||
if (!data.Event) {
|
||||
return;
|
||||
@@ -299,6 +360,34 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
map((event) => this.toWahaPresences(event.From || event.Chat, [event])),
|
||||
);
|
||||
this.events2.get(WAHAEvents.PRESENCE_UPDATE).switch(presenceUpdates$);
|
||||
//
|
||||
// Group Events
|
||||
//
|
||||
const joinedGroup$ = all$.pipe(onlyEvent(WhatsMeowEvent.JOINED_GROUP));
|
||||
const groupV2Join$ = joinedGroup$.pipe(map(ToGroupV2JoinEvent));
|
||||
this.events2.get(WAHAEvents.GROUP_V2_JOIN).switch(groupV2Join$);
|
||||
|
||||
const groupInfo$ = all$.pipe(onlyEvent(WhatsMeowEvent.GROUP_INFO));
|
||||
|
||||
const groupV2Leave$ = groupInfo$.pipe(
|
||||
map((event) => ToGroupV2LeaveEvent(this.me, event)),
|
||||
filter(Boolean),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_LEAVE).switch(groupV2Leave$);
|
||||
|
||||
const groupV2Participants$ = groupInfo$.pipe(
|
||||
map(ToGroupV2ParticipantsEvents),
|
||||
mergeMap((events) => events),
|
||||
);
|
||||
this.events2
|
||||
.get(WAHAEvents.GROUP_V2_PARTICIPANTS)
|
||||
.switch(groupV2Participants$);
|
||||
|
||||
const groupV2Update$ = groupInfo$.pipe(
|
||||
map(ToGroupV2UpdateEvent),
|
||||
filter(Boolean),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_UPDATE).switch(groupV2Update$);
|
||||
}
|
||||
|
||||
async fetchContactProfilePicture(id: string): Promise<string> {
|
||||
@@ -390,6 +479,40 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile methods
|
||||
*/
|
||||
public async setProfileName(name: string): Promise<boolean> {
|
||||
const request = new messages.ProfileNameRequest({
|
||||
session: this.session,
|
||||
name: name,
|
||||
});
|
||||
const response = await promisify(this.client.SetProfileName)(request);
|
||||
response.toObject();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async setProfileStatus(status: string): Promise<boolean> {
|
||||
const request = new messages.ProfileStatusRequest({
|
||||
session: this.session,
|
||||
status: status,
|
||||
});
|
||||
const response = await promisify(this.client.SetProfileStatus)(request);
|
||||
response.toObject();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected setProfilePicture(file: BinaryFile | RemoteFile): Promise<boolean> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
protected deleteProfilePicture(): Promise<boolean> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Other methods
|
||||
*/
|
||||
async sendText(request: MessageTextRequest) {
|
||||
const jid = toJID(this.ensureSuffix(request.chatId));
|
||||
const message = new messages.MessageRequest({
|
||||
@@ -402,11 +525,38 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
return this.messageResponse(jid, data);
|
||||
}
|
||||
|
||||
protected checkStatusRequest(request: StatusRequest) {
|
||||
if (request.contacts && request.contacts?.length > 0) {
|
||||
const msg =
|
||||
"GOWS doesn't accept 'contacts'. Remove the field to send status to all contacts.";
|
||||
throw new UnprocessableEntityException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public async sendTextStatus(status: TextStatus) {
|
||||
this.checkStatusRequest(status);
|
||||
|
||||
const message = new messages.MessageRequest({
|
||||
jid: Jid.BROADCAST,
|
||||
text: status.text,
|
||||
session: this.session,
|
||||
backgroundColor: new messages.OptionalString({
|
||||
value: status.backgroundColor,
|
||||
}),
|
||||
font: new messages.OptionalUInt32({
|
||||
value: status.font,
|
||||
}),
|
||||
});
|
||||
const response = await promisify(this.client.SendMessage)(message);
|
||||
const data = response.toObject();
|
||||
return this.messageResponse(Jid.BROADCAST, data);
|
||||
}
|
||||
|
||||
protected messageResponse(jid, data) {
|
||||
const id = buildMessageId({
|
||||
ID: data.id,
|
||||
IsFromMe: true,
|
||||
IsGroup: isJidGroup(jid),
|
||||
IsGroup: isJidGroup(jid) || isJidStatusBroadcast(jid),
|
||||
Chat: jid,
|
||||
Sender: this.me.id,
|
||||
});
|
||||
@@ -416,8 +566,20 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
};
|
||||
}
|
||||
|
||||
checkNumberStatus(request: CheckNumberStatusQuery) {
|
||||
throw new Error('Method not implemented.');
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const req = new messages.CheckPhonesRequest({
|
||||
session: this.session,
|
||||
phones: [request.phone],
|
||||
});
|
||||
const response = await promisify(this.client.CheckPhones)(req);
|
||||
const data = response.toObject();
|
||||
const info = data.infos[0];
|
||||
return {
|
||||
numberExists: info.registered,
|
||||
chatId: toCusFormat(info.jid),
|
||||
};
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
@@ -569,7 +731,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
return {
|
||||
participant: toCusFormat(data.From),
|
||||
lastKnownPresence: lastKnownPresence,
|
||||
lastSeen: parseTimestamp(data.LastSeen),
|
||||
lastSeen: parseTimestampToSeconds(data.LastSeen),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -606,11 +768,318 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels methods
|
||||
*/
|
||||
public searchChannelsByView(
|
||||
query: ChannelSearchByView,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
public searchChannelsByText(
|
||||
query: ChannelSearchByText,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
public async previewChannelMessages(
|
||||
inviteCode: string,
|
||||
query: PreviewChannelMessages,
|
||||
): Promise<ChannelMessage[]> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
protected toChannel(newsletter: messages.Newsletter): Channel {
|
||||
const role: ChannelRole =
|
||||
(newsletter.role?.toUpperCase() as ChannelRole) || ChannelRole.GUEST;
|
||||
let picture = newsletter.picture;
|
||||
if (picture.startsWith('/')) {
|
||||
picture = getUrlFromDirectPath(picture);
|
||||
}
|
||||
let preview = newsletter.preview;
|
||||
if (preview.startsWith('/')) {
|
||||
preview = getUrlFromDirectPath(preview);
|
||||
}
|
||||
return {
|
||||
id: newsletter.id,
|
||||
name: newsletter.name,
|
||||
description: newsletter.description,
|
||||
invite: getChannelInviteLink(newsletter.invite),
|
||||
picture: picture,
|
||||
preview: preview,
|
||||
verified: newsletter.verified,
|
||||
role: role,
|
||||
subscribersCount: newsletter.subscriberCount,
|
||||
};
|
||||
}
|
||||
|
||||
public async channelsList(query: ListChannelsQuery): Promise<Channel[]> {
|
||||
const request = new messages.NewsletterListRequest({
|
||||
session: this.session,
|
||||
});
|
||||
const response = await promisify(this.client.GetSubscribedNewsletters)(
|
||||
request,
|
||||
);
|
||||
const data = response.toObject();
|
||||
const newsletters = data.newsletters;
|
||||
let channels: Channel[] = newsletters.map(this.toChannel.bind(this));
|
||||
if (query.role) {
|
||||
// @ts-ignore
|
||||
channels = channels.filter((channel) => channel.role === query.role);
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
|
||||
public async channelsCreateChannel(
|
||||
request: CreateChannelRequest,
|
||||
): Promise<Channel> {
|
||||
const req = new messages.CreateNewsletterRequest({
|
||||
session: this.session,
|
||||
name: request.name,
|
||||
description: request.description,
|
||||
});
|
||||
const response = await promisify(this.client.CreateNewsletter)(req);
|
||||
const newsletter = response.toObject() as messages.Newsletter;
|
||||
return this.toChannel(newsletter);
|
||||
}
|
||||
|
||||
public async channelsGetChannel(id: string): Promise<Channel> {
|
||||
return await this.channelsGetChannelByInviteCode(id);
|
||||
}
|
||||
|
||||
public async channelsGetChannelByInviteCode(
|
||||
inviteCode: string,
|
||||
): Promise<Channel> {
|
||||
const request = new messages.NewsletterInfoRequest({
|
||||
session: this.session,
|
||||
id: inviteCode,
|
||||
});
|
||||
const response = await promisify(this.client.GetNewsletterInfo)(request);
|
||||
const newsletter = response.toObject() as messages.Newsletter;
|
||||
return this.toChannel(newsletter);
|
||||
}
|
||||
|
||||
public channelsFollowChannel(id: string): Promise<any> {
|
||||
return this.channelsToggleFollow(id, true);
|
||||
}
|
||||
|
||||
public channelsUnfollowChannel(id: string): Promise<any> {
|
||||
return this.channelsToggleFollow(id, false);
|
||||
}
|
||||
|
||||
protected async channelsToggleFollow(id: string, follow: boolean) {
|
||||
const request = new messages.NewsletterToggleFollowRequest({
|
||||
session: this.session,
|
||||
jid: id,
|
||||
follow: follow,
|
||||
});
|
||||
const response = await promisify(this.client.NewsletterToggleFollow)(
|
||||
request,
|
||||
);
|
||||
return response.toObject();
|
||||
}
|
||||
|
||||
public channelsMuteChannel(id: string): Promise<void> {
|
||||
return this.channelsToggleMute(id, true);
|
||||
}
|
||||
|
||||
public channelsUnmuteChannel(id: string): Promise<void> {
|
||||
return this.channelsToggleMute(id, false);
|
||||
}
|
||||
|
||||
protected async channelsToggleMute(id: string, mute: boolean): Promise<any> {
|
||||
const request = new messages.NewsletterToggleMuteRequest({
|
||||
session: this.session,
|
||||
jid: id,
|
||||
mute: mute,
|
||||
});
|
||||
const response = await promisify(this.client.NewsletterToggleMute)(request);
|
||||
return response.toObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
|
||||
protected toWAContact(contact) {
|
||||
return {
|
||||
id: toCusFormat(contact.Jid),
|
||||
name: contact.Name,
|
||||
pushname: contact.PushName,
|
||||
};
|
||||
}
|
||||
|
||||
public async getContact(query: ContactQuery) {
|
||||
const jid = toJID(query.contactId);
|
||||
const request = new messages.EntityByIdRequest({
|
||||
session: this.session,
|
||||
id: jid,
|
||||
});
|
||||
const response = await promisify(this.client.GetContact)(request);
|
||||
const data = parseJson(response);
|
||||
return this.toWAContact(data);
|
||||
}
|
||||
|
||||
public async getContacts(pagination: PaginationParams) {
|
||||
const request = new messages.GetContactsRequest({
|
||||
session: this.session,
|
||||
pagination: new messages.Pagination({
|
||||
limit: pagination.limit,
|
||||
offset: pagination.offset,
|
||||
}),
|
||||
sortBy: new messages.SortBy({
|
||||
field: pagination.sortBy || 'id',
|
||||
order:
|
||||
pagination.sortOrder === SortOrder.DESC
|
||||
? messages.SortBy.Order.DESC
|
||||
: messages.SortBy.Order.ASC,
|
||||
}),
|
||||
});
|
||||
const response = await promisify(this.client.GetContacts)(request);
|
||||
const data = parseJsonList(response);
|
||||
return data.map(this.toWAContact.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Chats methods
|
||||
*/
|
||||
public async getChatsOverview(
|
||||
pagination: PaginationParams,
|
||||
): Promise<ChatSummary[]> {
|
||||
if (!pagination.sortBy) {
|
||||
pagination.sortBy = 'timestamp';
|
||||
}
|
||||
if (!pagination.sortOrder) {
|
||||
pagination.sortOrder = SortOrder.DESC;
|
||||
}
|
||||
const chats = await this.getChats(pagination);
|
||||
|
||||
const promises = [];
|
||||
for (const chat of chats) {
|
||||
promises.push(this.fetchChatSummary(chat));
|
||||
}
|
||||
const result = await Promise.all(promises);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected async fetchChatSummary(chat): Promise<ChatSummary> {
|
||||
const id = toCusFormat(chat.id);
|
||||
const name = chat.name;
|
||||
const picture = await this.getContactProfilePicture(chat.id, false);
|
||||
const messages = await this.getChatMessages(
|
||||
chat.id,
|
||||
{ limit: 1, offset: 0, downloadMedia: false },
|
||||
{},
|
||||
);
|
||||
const message = messages.length > 0 ? messages[0] : null;
|
||||
return {
|
||||
id: id,
|
||||
name: name || null,
|
||||
picture: picture,
|
||||
lastMessage: message,
|
||||
_chat: chat,
|
||||
};
|
||||
}
|
||||
|
||||
protected toWAChat(chat) {
|
||||
return {
|
||||
id: toCusFormat(chat.Jid),
|
||||
name: chat.Name,
|
||||
conversationTimestamp: parseTimestampToSeconds(
|
||||
chat.ConversationTimestamp,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
public async getChats(pagination: PaginationParams) {
|
||||
if (pagination.sortBy === ChatSortField.CONVERSATION_TIMESTAMP) {
|
||||
pagination.sortBy = 'timestamp';
|
||||
}
|
||||
const request = new messages.GetChatsRequest({
|
||||
session: this.session,
|
||||
pagination: new messages.Pagination({
|
||||
limit: pagination.limit,
|
||||
offset: pagination.offset,
|
||||
}),
|
||||
sortBy: new messages.SortBy({
|
||||
field: pagination.sortBy || 'id',
|
||||
order:
|
||||
pagination.sortOrder === SortOrder.DESC
|
||||
? messages.SortBy.Order.DESC
|
||||
: messages.SortBy.Order.ASC,
|
||||
}),
|
||||
});
|
||||
const response = await promisify(this.client.GetChats)(request);
|
||||
const data = parseJsonList(response);
|
||||
return data.map(this.toWAChat.bind(this));
|
||||
}
|
||||
|
||||
public async getChatMessages(
|
||||
chatId: string,
|
||||
query: GetChatMessagesQuery,
|
||||
filter: GetChatMessagesFilter,
|
||||
) {
|
||||
const downloadMedia = query.downloadMedia;
|
||||
let jid: messages.OptionalString;
|
||||
if (chatId === 'all') {
|
||||
jid = null;
|
||||
} else {
|
||||
jid = new messages.OptionalString({
|
||||
value: toJID(this.ensureSuffix(chatId)),
|
||||
});
|
||||
}
|
||||
|
||||
const request = new messages.GetMessagesRequest({
|
||||
session: this.session,
|
||||
filters: new messages.MessageFilters({
|
||||
jid: jid,
|
||||
timestampGte: optional(
|
||||
filter['filter.timestamp.gte'],
|
||||
messages.OptionalUInt64,
|
||||
),
|
||||
timestampLte: optional(
|
||||
filter['filter.timestamp.lte'],
|
||||
messages.OptionalUInt64,
|
||||
),
|
||||
fromMe: optional(filter['filter.fromMe'], messages.OptionalBool),
|
||||
}),
|
||||
pagination: new messages.Pagination({
|
||||
limit: query.limit,
|
||||
offset: query.offset,
|
||||
}),
|
||||
});
|
||||
const response = await promisify(this.client.GetMessages)(request);
|
||||
const msgs = parseJsonList(response);
|
||||
const promises = [];
|
||||
for (const msg of msgs) {
|
||||
promises.push(this.processIncomingMessage(msg, downloadMedia));
|
||||
}
|
||||
let result = await Promise.all(promises);
|
||||
result = result.filter(Boolean);
|
||||
return result;
|
||||
}
|
||||
|
||||
public async getChatMessage(
|
||||
chatId: string,
|
||||
messageId: string,
|
||||
query: GetChatMessageQuery,
|
||||
): Promise<null | WAMessage> {
|
||||
const key = parseMessageIdSerialized(messageId, true);
|
||||
const request = new messages.EntityByIdRequest({
|
||||
session: this.session,
|
||||
id: key.id,
|
||||
});
|
||||
const response = await promisify(this.client.GetMessageById)(request);
|
||||
const msg = parseJson(response);
|
||||
return this.processIncomingMessage(msg, query.downloadMedia);
|
||||
}
|
||||
|
||||
//
|
||||
// END - Methods for API
|
||||
//
|
||||
|
||||
private async processIncomingMessage(message, downloadMedia = true) {
|
||||
protected async processIncomingMessage(message, downloadMedia = true) {
|
||||
// if there is no text or media message
|
||||
if (!message) return;
|
||||
if (!message.Message) return;
|
||||
@@ -642,19 +1111,26 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
const id = buildMessageId(message);
|
||||
const body = this.extractBody(message.Message);
|
||||
const replyTo = null; // TODO: this.extractReplyTo(message.message);
|
||||
const ack = null; // TODO: Extract
|
||||
|
||||
let ack;
|
||||
if (message.Status) {
|
||||
ack = statusToAck(message.Status);
|
||||
} else {
|
||||
ack = message.Info.IsFromMe ? WAMessageAck.SERVER : WAMessageAck.DEVICE;
|
||||
}
|
||||
const mediaContent = extractMediaContent(message.Message);
|
||||
|
||||
return {
|
||||
id: id,
|
||||
timestamp: parseTimestamp(message.Info.Timestamp),
|
||||
timestamp: parseTimestampToSeconds(message.Info.Timestamp),
|
||||
from: toCusFormat(fromToParticipant.from),
|
||||
fromMe: message.Info.IsFromMe,
|
||||
body: body,
|
||||
to: toCusFormat(fromToParticipant.to),
|
||||
participant: toCusFormat(fromToParticipant.participant),
|
||||
// Media
|
||||
hasMedia: Boolean(message.media),
|
||||
media: message.media,
|
||||
hasMedia: Boolean(mediaContent),
|
||||
media: message.media || null,
|
||||
mediaUrl: message.media?.url,
|
||||
// @ts-ignore
|
||||
ack: ack,
|
||||
@@ -773,7 +1249,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
|
||||
const messageId = this.buildMessageIdFromKey(reactionMessage.key);
|
||||
const reaction: WAMessageReaction = {
|
||||
id: id,
|
||||
timestamp: parseTimestamp(message.Info.Timestamp),
|
||||
timestamp: parseTimestampToSeconds(message.Info.Timestamp),
|
||||
from: toCusFormat(fromToParticipant.from),
|
||||
fromMe: message.Info.IsFromMe,
|
||||
to: toCusFormat(fromToParticipant.to),
|
||||
@@ -822,6 +1298,7 @@ export class GOWSEngineMediaProcessor implements IMediaEngineProcessor<any> {
|
||||
async getMediaBuffer(message: any): Promise<Buffer | null> {
|
||||
const data = JSON.stringify(message.Message);
|
||||
const request = new messages.DownloadMediaRequest({
|
||||
// double "session" it's not a mistake here
|
||||
session: this.session.session,
|
||||
message: data,
|
||||
});
|
||||
@@ -838,16 +1315,6 @@ export class GOWSEngineMediaProcessor implements IMediaEngineProcessor<any> {
|
||||
}
|
||||
}
|
||||
|
||||
export function extractMediaContent(message: any) {
|
||||
const mediaContent =
|
||||
message?.documentMessage ||
|
||||
message?.imageMessage ||
|
||||
message?.videoMessage ||
|
||||
message?.audioMessage ||
|
||||
message?.stickerMessage;
|
||||
return mediaContent;
|
||||
}
|
||||
|
||||
function isMine(message) {
|
||||
return !!message.Info.IsFromMe;
|
||||
}
|
||||
@@ -894,3 +1361,11 @@ function parseTimestamp(timestamp: string): number {
|
||||
// "2024-12-25T14:28:42+03:00" => 1234567890
|
||||
return new Date(timestamp).getTime();
|
||||
}
|
||||
|
||||
function parseTimestampToSeconds(timestamp: string): number {
|
||||
const ms = parseTimestamp(timestamp);
|
||||
if (!ms) {
|
||||
return ms;
|
||||
}
|
||||
return Math.floor(ms / 1000);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// JID just a string alias, we dump it as String in golang
|
||||
type JID = string;
|
||||
|
||||
interface GroupName {
|
||||
Name: string;
|
||||
NameSetAt: string; // ISO string format for time
|
||||
NameSetBy: JID;
|
||||
}
|
||||
|
||||
interface GroupTopic {
|
||||
Topic: string;
|
||||
TopicID: string;
|
||||
TopicSetAt: string;
|
||||
TopicSetBy: JID;
|
||||
TopicDeleted: boolean;
|
||||
}
|
||||
|
||||
interface GroupLocked {
|
||||
IsLocked: boolean;
|
||||
}
|
||||
|
||||
interface GroupAnnounce {
|
||||
IsAnnounce: boolean;
|
||||
AnnounceVersionID: string;
|
||||
}
|
||||
|
||||
interface GroupEphemeral {
|
||||
IsEphemeral: boolean;
|
||||
DisappearingTimer: number;
|
||||
}
|
||||
|
||||
interface GroupMembershipApprovalMode {
|
||||
IsJoinApprovalRequired: boolean;
|
||||
}
|
||||
|
||||
interface GroupDelete {
|
||||
Deleted: boolean;
|
||||
DeleteReason: string;
|
||||
}
|
||||
|
||||
interface GroupLinkTarget {
|
||||
JID: JID;
|
||||
GroupName: GroupName;
|
||||
GroupIsDefaultSub: GroupIsDefaultSub;
|
||||
}
|
||||
|
||||
interface GroupLinkChange {
|
||||
Type: string; // Enum in Go: GroupLinkChangeType
|
||||
UnlinkReason: string; // Enum in Go: GroupUnlinkReason
|
||||
Group: GroupLinkTarget;
|
||||
}
|
||||
|
||||
interface GroupIsDefaultSub {
|
||||
IsDefaultSubGroup: boolean;
|
||||
}
|
||||
|
||||
export interface GroupInfoEvent {
|
||||
JID: JID;
|
||||
Notify: string;
|
||||
Sender?: JID;
|
||||
Timestamp: string;
|
||||
|
||||
Name?: GroupName;
|
||||
Topic?: GroupTopic;
|
||||
Locked?: GroupLocked;
|
||||
Announce?: GroupAnnounce;
|
||||
Ephemeral?: GroupEphemeral;
|
||||
|
||||
MembershipApprovalMode?: GroupMembershipApprovalMode;
|
||||
Delete?: GroupDelete;
|
||||
|
||||
Link?: GroupLinkChange;
|
||||
Unlink?: GroupLinkChange;
|
||||
NewInviteLink?: string;
|
||||
|
||||
PrevParticipantVersionID: string;
|
||||
ParticipantVersionID: string;
|
||||
|
||||
JoinReason: string;
|
||||
|
||||
Join: JID[];
|
||||
Leave: JID[];
|
||||
Promote: JID[];
|
||||
Demote: JID[];
|
||||
}
|
||||
|
||||
export interface GOWSGroupParticipant {
|
||||
JID: JID;
|
||||
IsAdmin: boolean;
|
||||
IsSuperAdmin: boolean;
|
||||
}
|
||||
|
||||
export interface GroupInfoFull {
|
||||
JID: JID;
|
||||
OwnerJID: JID;
|
||||
Name: string; // Name has additional properties here
|
||||
Topic: string; // Topic has additional properties here
|
||||
IsLocked: boolean; // specifies whether the group info can only be edited by admins.
|
||||
IsAnnounce: boolean; // specifies whether only admins can send messages in the group
|
||||
Participants: GOWSGroupParticipant[];
|
||||
MemberAddMode: string; // all_member_add | admin_add
|
||||
IsJoinApprovalRequired: boolean;
|
||||
}
|
||||
|
||||
export interface JoinedGroupEvent extends GroupInfoFull {
|
||||
Reason: string;
|
||||
Type: string;
|
||||
}
|
||||
@@ -22,3 +22,20 @@ export interface ChatPresence {
|
||||
State: ChatPresenceState;
|
||||
Media: ChatPresenceMedia;
|
||||
}
|
||||
|
||||
/**
|
||||
* StatusError Status = 0
|
||||
* StatusPending Status = 1
|
||||
* StatusServerAck Status = 2
|
||||
* StatusDeliveryAck Status = 3
|
||||
* StatusRead Status = 4
|
||||
* StatusPlayed Status = 5
|
||||
*/
|
||||
export enum MessageStatus {
|
||||
Error = 0,
|
||||
Pending = 1,
|
||||
ServerAck = 2,
|
||||
DeliveryAck = 3,
|
||||
Read = 4,
|
||||
Played = 5,
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import { GroupMetadata, jidNormalizedUser } from '@adiwajshing/baileys';
|
||||
import type { Contact } from '@adiwajshing/baileys/lib/Types/Contact';
|
||||
import {
|
||||
GroupParticipant as NOWEBGroupParticipant,
|
||||
ParticipantAction,
|
||||
} from '@adiwajshing/baileys/lib/Types/GroupMetadata';
|
||||
import { getGroupInviteLink } from '@waha/core/abc/session.abc';
|
||||
import { toCusFormat } from '@waha/core/engines/noweb/session.noweb.core';
|
||||
import {
|
||||
GroupInfo,
|
||||
GroupParticipant,
|
||||
GroupParticipantRole,
|
||||
} from '@waha/structures/groups.dto';
|
||||
import {
|
||||
GroupParticipantType,
|
||||
GroupV2JoinEvent,
|
||||
GroupV2LeaveEvent,
|
||||
GroupV2ParticipantsEvent,
|
||||
GroupV2UpdateEvent,
|
||||
} from '@waha/structures/groups.events.dto';
|
||||
|
||||
export function ToGroupInfo(group: Partial<GroupMetadata>): GroupInfo {
|
||||
let participants: GroupParticipant[] = undefined;
|
||||
if (group.participants && group.participants.length > 0) {
|
||||
participants = group.participants.map(ToGroupParticipant);
|
||||
}
|
||||
return {
|
||||
id: group.id,
|
||||
subject: group.subject,
|
||||
description: group.desc,
|
||||
invite: group.inviteCode ? getGroupInviteLink(group.inviteCode) : undefined,
|
||||
participants: participants,
|
||||
membersCanAddNewMember: group.memberAddMode,
|
||||
membersCanSendMessages: group.announce,
|
||||
newMembersApprovalRequired: group.joinApprovalMode,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2JoinEvent(group: GroupMetadata): GroupV2JoinEvent {
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
group: ToGroupInfo(group),
|
||||
_data: group,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupParticipant(
|
||||
participant: NOWEBGroupParticipant,
|
||||
): GroupParticipant {
|
||||
let role: GroupParticipantRole = GroupParticipantRole.PARTICIPANT;
|
||||
if (participant.admin === 'admin') {
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
} else if (participant.admin === 'superadmin') {
|
||||
role = GroupParticipantRole.SUPERADMIN;
|
||||
}
|
||||
return {
|
||||
id: toCusFormat(participant.id),
|
||||
role: role,
|
||||
};
|
||||
}
|
||||
|
||||
interface GroupParticipantUpdate {
|
||||
id: string;
|
||||
author: string;
|
||||
participants: string[];
|
||||
action: ParticipantAction;
|
||||
}
|
||||
|
||||
export function ToGroupV2Participants(
|
||||
update: GroupParticipantUpdate,
|
||||
): GroupV2ParticipantsEvent {
|
||||
let role: GroupParticipantRole;
|
||||
let type: GroupParticipantType;
|
||||
switch (update.action) {
|
||||
case 'add':
|
||||
role = GroupParticipantRole.PARTICIPANT;
|
||||
type = GroupParticipantType.JOIN;
|
||||
break;
|
||||
case 'remove':
|
||||
role = GroupParticipantRole.LEFT;
|
||||
type = GroupParticipantType.LEAVE;
|
||||
break;
|
||||
case 'promote':
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
type = GroupParticipantType.PROMOTE;
|
||||
break;
|
||||
case 'demote':
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
type = GroupParticipantType.DEMOTE;
|
||||
break;
|
||||
}
|
||||
|
||||
const participants: GroupParticipant[] = update.participants.map((id) => {
|
||||
return {
|
||||
id: toCusFormat(id),
|
||||
role: role,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
group: {
|
||||
id: toCusFormat(update.id),
|
||||
},
|
||||
type: type,
|
||||
timestamp: Date.now(),
|
||||
participants: participants,
|
||||
_data: update,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2UpdateEvent(
|
||||
group: Partial<GroupMetadata>,
|
||||
): GroupV2UpdateEvent {
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
group: ToGroupInfo(group),
|
||||
_data: group,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2LeaveEvent(
|
||||
me: Contact,
|
||||
update: GroupParticipantUpdate,
|
||||
): GroupV2LeaveEvent | null {
|
||||
if (update.action !== 'remove') {
|
||||
return null;
|
||||
}
|
||||
if (!me) {
|
||||
return null;
|
||||
}
|
||||
const meId = jidNormalizedUser(me.id);
|
||||
if (!update.participants.includes(meId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
group: {
|
||||
id: toCusFormat(update.id),
|
||||
},
|
||||
_data: update,
|
||||
};
|
||||
}
|
||||
@@ -40,6 +40,12 @@ import { MessageUserReceiptUpdate } from '@adiwajshing/baileys/lib/Types/Message
|
||||
import { isLidUser } from '@adiwajshing/baileys/lib/WABinary/jid-utils';
|
||||
import { Logger as BaileysLogger } from '@adiwajshing/baileys/node_modules/pino';
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
import {
|
||||
ToGroupV2JoinEvent,
|
||||
ToGroupV2LeaveEvent,
|
||||
ToGroupV2Participants,
|
||||
ToGroupV2UpdateEvent,
|
||||
} from '@waha/core/engines/noweb/groups.noweb';
|
||||
import { sendButtonMessage } from '@waha/core/engines/noweb/noweb.buttons';
|
||||
import { NowebInMemoryStore } from '@waha/core/engines/noweb/store/NowebInMemoryStore';
|
||||
import { IMediaEngineProcessor } from '@waha/core/media/IMediaEngineProcessor';
|
||||
@@ -48,9 +54,14 @@ import { PairingCodeResponse } from '@waha/structures/auth.dto';
|
||||
import { CallData } from '@waha/structures/calls.dto';
|
||||
import {
|
||||
Channel,
|
||||
ChannelListResult,
|
||||
ChannelMessage,
|
||||
ChannelRole,
|
||||
ChannelSearchByText,
|
||||
ChannelSearchByView,
|
||||
CreateChannelRequest,
|
||||
ListChannelsQuery,
|
||||
PreviewChannelMessages,
|
||||
} from '@waha/structures/channels.dto';
|
||||
import {
|
||||
ChatSummary,
|
||||
@@ -75,6 +86,7 @@ import {
|
||||
PollVote,
|
||||
PollVotePayload,
|
||||
WAMessageAckBody,
|
||||
WAMessageRevokedBody,
|
||||
} from '@waha/structures/webhooks.dto';
|
||||
import { LoggerBuilder } from '@waha/utils/logging';
|
||||
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
|
||||
@@ -149,6 +161,7 @@ import {
|
||||
import {
|
||||
ensureSuffix,
|
||||
getChannelInviteLink,
|
||||
getPublicUrlFromDirectPath,
|
||||
isNewsletter,
|
||||
WhatsappSession,
|
||||
} from '../../abc/session.abc';
|
||||
@@ -642,6 +655,27 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile methods
|
||||
*/
|
||||
public async setProfileName(name: string): Promise<boolean> {
|
||||
await this.sock.updateProfileName(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async setProfileStatus(status: string): Promise<boolean> {
|
||||
await this.sock.updateProfileStatus(status);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected setProfilePicture(file: BinaryFile | RemoteFile): Promise<boolean> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
protected deleteProfilePicture(): Promise<boolean> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Other methods
|
||||
*/
|
||||
@@ -1104,10 +1138,6 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
return contacts.map(this.toWAContact);
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async fetchContactProfilePicture(id: string) {
|
||||
const contact = this.ensureSuffix(id);
|
||||
if (isJidNewsletter(id)) {
|
||||
@@ -1316,6 +1346,25 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
/**
|
||||
* Channels methods
|
||||
*/
|
||||
public searchChannelsByView(
|
||||
query: ChannelSearchByView,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
public searchChannelsByText(
|
||||
query: ChannelSearchByText,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
public async previewChannelMessages(
|
||||
inviteCode: string,
|
||||
query: PreviewChannelMessages,
|
||||
): Promise<ChannelMessage[]> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
protected toChannel(newsletter: NewsletterMetadata): Channel {
|
||||
const role =
|
||||
// @ts-ignore
|
||||
@@ -1323,20 +1372,21 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
(newsletter.viewer_metadata?.view_role as ChannelRole) ||
|
||||
ChannelRole.GUEST;
|
||||
const preview = newsletter.preview
|
||||
? getUrlFromDirectPath(newsletter.preview)
|
||||
? getPublicUrlFromDirectPath(newsletter.preview)
|
||||
: null;
|
||||
const picture = newsletter.picture
|
||||
? getUrlFromDirectPath(newsletter.picture)
|
||||
? getPublicUrlFromDirectPath(newsletter.picture)
|
||||
: null;
|
||||
return {
|
||||
id: newsletter.id,
|
||||
name: newsletter.name,
|
||||
description: newsletter.description,
|
||||
invite: getChannelInviteLink(newsletter.invite),
|
||||
preview: preview,
|
||||
picture: picture,
|
||||
preview: preview || picture,
|
||||
picture: picture || preview,
|
||||
verified: newsletter.verification === 'VERIFIED',
|
||||
role: role,
|
||||
subscribersCount: newsletter.subscribers,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1426,6 +1476,24 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
this.events2.get(WAHAEvents.MESSAGE).switch(messagesFromOthers$);
|
||||
this.events2.get(WAHAEvents.MESSAGE_ANY).switch(messagesFromAll$);
|
||||
|
||||
const messagesRevoked$ = messagesUpsert$.pipe(
|
||||
// @ts-ignore
|
||||
filter(
|
||||
(message) =>
|
||||
message.message.protocolMessage?.type ===
|
||||
proto.Message.ProtocolMessage.Type.REVOKE,
|
||||
),
|
||||
mergeMap(async (message): Promise<WAMessageRevokedBody> => {
|
||||
const afterMessage = await this.toWAMessage(message);
|
||||
return {
|
||||
after: afterMessage,
|
||||
before: null,
|
||||
_data: message,
|
||||
};
|
||||
}),
|
||||
);
|
||||
this.events2.get(WAHAEvents.MESSAGE_REVOKED).switch(messagesRevoked$);
|
||||
|
||||
//
|
||||
// Message Reactions
|
||||
//
|
||||
@@ -1469,12 +1537,51 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
this.events2
|
||||
.get(WAHAEvents.STATE_CHANGE)
|
||||
.switch(fromEvent(this.sock.ev, 'connection.update'));
|
||||
this.events2.get(WAHAEvents.GROUP_JOIN).switch(
|
||||
|
||||
const groupsUpsert$: Observable<GroupMetadata> = fromEvent(
|
||||
this.sock.ev,
|
||||
'groups.upsert',
|
||||
).pipe(
|
||||
// @ts-ignore
|
||||
fromEvent<GroupMetadata[]>(this.sock.ev, 'groups.upsert').pipe(
|
||||
mergeAll(),
|
||||
),
|
||||
mergeAll(),
|
||||
);
|
||||
const groupsUpdate$: Observable<Partial<GroupMetadata>> = fromEvent(
|
||||
this.sock.ev,
|
||||
'groups.update',
|
||||
).pipe(
|
||||
// @ts-ignore
|
||||
mergeAll(),
|
||||
);
|
||||
const groupsParticipantsUpdate$: Observable<any> = fromEvent(
|
||||
this.sock.ev,
|
||||
'group-participants.update',
|
||||
);
|
||||
|
||||
this.events2.get(WAHAEvents.GROUP_JOIN).switch(groupsUpsert$);
|
||||
|
||||
const groupV2Join$ = groupsUpsert$.pipe(
|
||||
map((group) => ToGroupV2JoinEvent(group)),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_JOIN).switch(groupV2Join$);
|
||||
|
||||
const groupV2Update$ = merge(groupsUpdate$).pipe(map(ToGroupV2UpdateEvent));
|
||||
this.events2.get(WAHAEvents.GROUP_V2_UPDATE).switch(groupV2Update$);
|
||||
|
||||
const groupV2Participants$ = groupsParticipantsUpdate$.pipe(
|
||||
map(ToGroupV2Participants),
|
||||
);
|
||||
this.events2
|
||||
.get(WAHAEvents.GROUP_V2_PARTICIPANTS)
|
||||
.switch(groupV2Participants$);
|
||||
|
||||
const groupV2Leave$ = groupsParticipantsUpdate$.pipe(
|
||||
map((group) =>
|
||||
ToGroupV2LeaveEvent(this.sock?.authState?.creds?.me, group),
|
||||
),
|
||||
filter(Boolean),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_LEAVE).switch(groupV2Leave$);
|
||||
|
||||
this.events2
|
||||
.get(WAHAEvents.PRESENCE_UPDATE)
|
||||
.switch(
|
||||
@@ -1636,7 +1743,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
return reaction;
|
||||
}
|
||||
|
||||
private async processIncomingMessage(message, downloadMedia = true) {
|
||||
protected async processIncomingMessage(message, downloadMedia = true) {
|
||||
// if there is no text or media message
|
||||
if (!message) return;
|
||||
if (!message.message) return;
|
||||
@@ -1644,6 +1751,12 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
if (message.message.reactionMessage) return;
|
||||
// Ignore poll votes, we have dedicated handler for that
|
||||
if (message.message.pollUpdateMessage) return;
|
||||
// Ignore revoke, we have a dedicated handler for that
|
||||
if (
|
||||
message.message.protocolMessage?.type ===
|
||||
proto.Message.ProtocolMessage.Type.REVOKE
|
||||
)
|
||||
return;
|
||||
|
||||
if (downloadMedia) {
|
||||
try {
|
||||
@@ -1670,17 +1783,18 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
const body = this.extractBody(message.message);
|
||||
const replyTo = this.extractReplyTo(message.message);
|
||||
const ack = message.ack || message.status - 1;
|
||||
const mediaContent = extractMediaContent(message.message);
|
||||
return Promise.resolve({
|
||||
id: id,
|
||||
timestamp: ensureNumber(message.messageTimestamp),
|
||||
from: toCusFormat(fromToParticipant.from),
|
||||
fromMe: message.key.fromMe,
|
||||
body: body,
|
||||
body: body || null,
|
||||
to: toCusFormat(fromToParticipant.to),
|
||||
participant: toCusFormat(fromToParticipant.participant),
|
||||
// Media
|
||||
hasMedia: Boolean(message.media),
|
||||
media: message.media,
|
||||
hasMedia: Boolean(mediaContent),
|
||||
media: message.media || null,
|
||||
mediaUrl: message.media?.url,
|
||||
// @ts-ignore
|
||||
ack: ack,
|
||||
@@ -1697,21 +1811,28 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
if (!message) {
|
||||
return null;
|
||||
}
|
||||
let body = message.conversation;
|
||||
const content = extractMessageContent(message);
|
||||
if (!content) {
|
||||
return null;
|
||||
}
|
||||
let body = content.conversation || null;
|
||||
if (!body) {
|
||||
// Some of the messages have no conversation, but instead have text in extendedTextMessage
|
||||
// https://github.com/devlikeapro/waha/issues/90
|
||||
body = message.extendedTextMessage?.text;
|
||||
body = content.extendedTextMessage?.text;
|
||||
}
|
||||
if (!body) {
|
||||
// Populate from caption
|
||||
const mediaContent = extractMediaContent(message);
|
||||
const mediaContent = extractMediaContent(content);
|
||||
// @ts-ignore - AudioMessage doesn't have caption field
|
||||
body = mediaContent?.caption;
|
||||
}
|
||||
// Response for buttons
|
||||
if (!body) {
|
||||
body = message.templateButtonReplyMessage?.selectedDisplayText;
|
||||
body = content.templateButtonReplyMessage?.selectedDisplayText;
|
||||
}
|
||||
if (!body) {
|
||||
body = content.buttonsResponseMessage?.selectedDisplayText;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { extractMessageContent, proto } from '@adiwajshing/baileys';
|
||||
|
||||
export function extractMediaContent(
|
||||
content: proto.IMessage | null | undefined,
|
||||
content: any | proto.IMessage | null | undefined,
|
||||
) {
|
||||
content = extractMessageContent(content);
|
||||
const mediaContent =
|
||||
|
||||
@@ -18,17 +18,32 @@ const { LoadPaginator } = require('./_Paginator.js');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const ChatFactory = require('whatsapp-web.js/src/factories/ChatFactory');
|
||||
|
||||
export class WebjsClient extends Client {
|
||||
export class WebjsClientCore extends Client {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
// Wait until it's READY and inject more utils
|
||||
this.on(Events.READY, async () => {
|
||||
await this.pupPage.evaluate(LoadLodash);
|
||||
await this.pupPage.evaluate(LoadPaginator);
|
||||
await this.pupPage.evaluate(LoadWAHA);
|
||||
await this.injectWaha();
|
||||
});
|
||||
}
|
||||
|
||||
async injectWaha() {
|
||||
await this.pupPage.evaluate(LoadLodash);
|
||||
await this.pupPage.evaluate(LoadPaginator);
|
||||
await this.pupPage.evaluate(LoadWAHA);
|
||||
}
|
||||
|
||||
async setPushName(name: string) {
|
||||
await this.pupPage.evaluate(async (pushName) => {
|
||||
return await window['WAHA'].WAWebSetPushnameConnAction.setPushname(
|
||||
pushName,
|
||||
);
|
||||
}, name);
|
||||
if (this.info) {
|
||||
this.info.pushname = name;
|
||||
}
|
||||
}
|
||||
|
||||
async unpair() {
|
||||
await this.pupPage.evaluate(async () => {
|
||||
if (
|
||||
@@ -11,4 +11,14 @@ exports.LoadWAHA = () => {
|
||||
const chatPromises = chats.map((chat) => window.WWebJS.getChatModel(chat));
|
||||
return await Promise.all(chatPromises);
|
||||
};
|
||||
|
||||
// Set push name
|
||||
window.WAHA.WAWebSetPushnameConnAction = window.require(
|
||||
'WAWebSetPushnameConnAction',
|
||||
);
|
||||
|
||||
// Get my status
|
||||
window.WAHA.WAWebTextStatusCollection = window.require(
|
||||
'WAWebTextStatusCollection',
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,154 @@
|
||||
import { WebjsClientCore } from '@waha/core/engines/webjs/WebjsClientCore';
|
||||
import {
|
||||
GroupId,
|
||||
GroupInfo,
|
||||
GroupParticipant,
|
||||
GroupParticipantRole,
|
||||
} from '@waha/structures/groups.dto';
|
||||
import {
|
||||
GroupParticipantType,
|
||||
GroupV2JoinEvent,
|
||||
GroupV2LeaveEvent,
|
||||
GroupV2ParticipantsEvent,
|
||||
GroupV2UpdateEvent,
|
||||
} from '@waha/structures/groups.events.dto';
|
||||
import {
|
||||
GroupChat,
|
||||
GroupNotification,
|
||||
GroupNotificationTypes,
|
||||
GroupParticipant as WEBJSGroupParticipant,
|
||||
} from 'whatsapp-web.js';
|
||||
|
||||
function ToGroupInfo(
|
||||
group: GroupChat,
|
||||
invite: string,
|
||||
participants = [],
|
||||
): GroupInfo {
|
||||
// @ts-ignore
|
||||
const groupMetadata = group.groupMetadata;
|
||||
const info: GroupInfo = {
|
||||
// @ts-ignore
|
||||
id: group.id._serialized,
|
||||
subject: group.name,
|
||||
description: group.description,
|
||||
invite: invite,
|
||||
membersCanAddNewMember: groupMetadata.restrict,
|
||||
membersCanSendMessages: groupMetadata.announce,
|
||||
newMembersApprovalRequired: groupMetadata.membershipApprovalMode,
|
||||
participants: participants,
|
||||
};
|
||||
return info;
|
||||
}
|
||||
|
||||
export async function ToGroupV2JoinEvent(
|
||||
client: WebjsClientCore,
|
||||
me: string,
|
||||
notification: GroupNotification,
|
||||
): Promise<GroupV2JoinEvent | null> {
|
||||
if (!notification.recipientIds.includes(me)) {
|
||||
return null;
|
||||
}
|
||||
// @ts-ignore
|
||||
const group: GroupChat = await client.getChatById(notification.id.remote);
|
||||
const invite = await group.getInviteCode();
|
||||
const participants = getParticipants(group.participants);
|
||||
const info: GroupInfo = ToGroupInfo(group, invite, participants);
|
||||
return {
|
||||
timestamp: notification.timestamp,
|
||||
group: info,
|
||||
_data: notification,
|
||||
};
|
||||
}
|
||||
|
||||
function getParticipants(
|
||||
participants: WEBJSGroupParticipant[],
|
||||
): GroupParticipant[] {
|
||||
return participants.map((participant) => {
|
||||
let role: GroupParticipantRole = GroupParticipantRole.PARTICIPANT;
|
||||
if (participant.isSuperAdmin) {
|
||||
role = GroupParticipantRole.SUPERADMIN;
|
||||
} else if (participant.isAdmin) {
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
}
|
||||
|
||||
return {
|
||||
id: participant.id._serialized,
|
||||
role: role,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function ToGroupV2LeaveEvent(
|
||||
me: string,
|
||||
notification: GroupNotification,
|
||||
): GroupV2LeaveEvent | null {
|
||||
if (!notification.recipientIds.includes(me)) {
|
||||
return null;
|
||||
}
|
||||
const group: GroupId = {
|
||||
// @ts-ignore
|
||||
id: notification.id.remote,
|
||||
};
|
||||
return {
|
||||
timestamp: notification.timestamp,
|
||||
group: group,
|
||||
_data: notification,
|
||||
};
|
||||
}
|
||||
|
||||
export async function ToGroupV2UpdateEvent(
|
||||
client: WebjsClientCore,
|
||||
notification: GroupNotification,
|
||||
): Promise<GroupV2UpdateEvent> {
|
||||
// @ts-ignore
|
||||
const group: GroupChat = await client.getChatById(notification.id.remote);
|
||||
const invite = await group.getInviteCode();
|
||||
const info: GroupInfo = ToGroupInfo(group, invite, undefined);
|
||||
return {
|
||||
group: info,
|
||||
timestamp: notification.timestamp,
|
||||
_data: notification,
|
||||
};
|
||||
}
|
||||
|
||||
export function ToGroupV2ParticipantsEvent(
|
||||
notification: GroupNotification,
|
||||
): GroupV2ParticipantsEvent | null {
|
||||
let type: GroupParticipantType;
|
||||
let role: GroupParticipantRole;
|
||||
if (['add', 'invite', 'linked_group_join'].includes(notification.type)) {
|
||||
type = GroupParticipantType.JOIN;
|
||||
role = GroupParticipantRole.PARTICIPANT;
|
||||
} else if (['remove', 'leave'].includes(notification.type)) {
|
||||
type = GroupParticipantType.LEAVE;
|
||||
role = GroupParticipantRole.LEFT;
|
||||
} else if (['promote'].includes(notification.type)) {
|
||||
type = GroupParticipantType.PROMOTE;
|
||||
role = GroupParticipantRole.ADMIN;
|
||||
} else if (['demote'].includes(notification.type)) {
|
||||
type = GroupParticipantType.DEMOTE;
|
||||
role = GroupParticipantRole.PARTICIPANT;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
const participants: GroupParticipant[] = notification.recipientIds.map(
|
||||
(id) => {
|
||||
return {
|
||||
id: id,
|
||||
role: role,
|
||||
};
|
||||
},
|
||||
);
|
||||
const group: GroupId = {
|
||||
// @ts-ignore
|
||||
id: notification.id.remote,
|
||||
};
|
||||
return {
|
||||
group: group,
|
||||
type: type,
|
||||
timestamp: notification.timestamp,
|
||||
participants: participants,
|
||||
_data: notification,
|
||||
};
|
||||
}
|
||||
@@ -3,8 +3,14 @@ import {
|
||||
getChannelInviteLink,
|
||||
WhatsappSession,
|
||||
} from '@waha/core/abc/session.abc';
|
||||
import {
|
||||
ToGroupV2JoinEvent,
|
||||
ToGroupV2LeaveEvent,
|
||||
ToGroupV2ParticipantsEvent,
|
||||
ToGroupV2UpdateEvent,
|
||||
} from '@waha/core/engines/webjs/groups.webjs';
|
||||
import { LocalAuth } from '@waha/core/engines/webjs/LocalAuth';
|
||||
import { WebjsClient } from '@waha/core/engines/webjs/WebjsClient';
|
||||
import { WebjsClientCore } from '@waha/core/engines/webjs/WebjsClientCore';
|
||||
import {
|
||||
AvailableInPlusVersion,
|
||||
NotImplementedByEngineError,
|
||||
@@ -15,9 +21,14 @@ import { splitAt } from '@waha/helpers';
|
||||
import { PairingCodeResponse } from '@waha/structures/auth.dto';
|
||||
import {
|
||||
Channel,
|
||||
ChannelListResult,
|
||||
ChannelMessage,
|
||||
ChannelRole,
|
||||
ChannelSearchByText,
|
||||
ChannelSearchByView,
|
||||
CreateChannelRequest,
|
||||
ListChannelsQuery,
|
||||
PreviewChannelMessages,
|
||||
} from '@waha/structures/channels.dto';
|
||||
import {
|
||||
ChatSortField,
|
||||
@@ -52,6 +63,7 @@ import {
|
||||
WAHASessionStatus,
|
||||
WAMessageAck,
|
||||
} from '@waha/structures/enums.dto';
|
||||
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
GroupSortField,
|
||||
@@ -72,9 +84,9 @@ import { PaginatorInMemory } from '@waha/utils/Paginator';
|
||||
import { sleep, waitUntil } from '@waha/utils/promiseTimeout';
|
||||
import { SingleDelayedJobRunner } from '@waha/utils/SingleDelayedJobRunner';
|
||||
import * as lodash from 'lodash';
|
||||
import { fromEvent, merge, mergeMap, Observable } from 'rxjs';
|
||||
import { filter, fromEvent, merge, mergeMap, Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import WAWebJS, {
|
||||
import {
|
||||
Call,
|
||||
Channel as WEBJSChannel,
|
||||
Chat,
|
||||
@@ -82,6 +94,7 @@ import WAWebJS, {
|
||||
Contact,
|
||||
Events,
|
||||
GroupChat,
|
||||
GroupNotification,
|
||||
Label as WEBJSLabel,
|
||||
Location,
|
||||
Message,
|
||||
@@ -106,7 +119,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
private engineStateCheckDelayedJob: SingleDelayedJobRunner;
|
||||
private shouldRestart: boolean;
|
||||
|
||||
whatsapp: WebjsClient;
|
||||
whatsapp: WebjsClientCore;
|
||||
protected qr: QR;
|
||||
|
||||
public constructor(config) {
|
||||
@@ -169,7 +182,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
rmMaxRetries: undefined,
|
||||
});
|
||||
this.addProxyConfig(clientOptions);
|
||||
return new WebjsClient(clientOptions);
|
||||
return new WebjsClientCore(clientOptions);
|
||||
}
|
||||
|
||||
private restartClient() {
|
||||
@@ -450,6 +463,30 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Profile methods
|
||||
*/
|
||||
public async setProfileName(name: string): Promise<boolean> {
|
||||
await this.whatsapp.setPushName(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async setProfileStatus(status: string): Promise<boolean> {
|
||||
await this.whatsapp.setStatus(status);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected setProfilePicture(file: BinaryFile | RemoteFile): Promise<boolean> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
protected deleteProfilePicture(): Promise<boolean> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Other methods
|
||||
*/
|
||||
sendText(request: MessageTextRequest) {
|
||||
const options = this.getMessageOptions(request);
|
||||
return this.whatsapp.sendMessage(
|
||||
@@ -479,7 +516,11 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
const options = this.getMessageOptions(request);
|
||||
return this.whatsapp.sendMessage(request.chatId, request.text, options);
|
||||
return this.whatsapp.sendMessage(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.text,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
@@ -499,12 +540,16 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
name: request.title,
|
||||
});
|
||||
const options = this.getMessageOptions(request);
|
||||
return this.whatsapp.sendMessage(request.chatId, location, options);
|
||||
return this.whatsapp.sendMessage(
|
||||
this.ensureSuffix(request.chatId),
|
||||
location,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
async forwardMessage(request: MessageForwardRequest): Promise<WAMessage> {
|
||||
const forwardMessage = this.recreateMessage(request.messageId);
|
||||
const msg = await forwardMessage.forward(request.chatId);
|
||||
const msg = await forwardMessage.forward(this.ensureSuffix(request.chatId));
|
||||
// Return "sent: true" for now
|
||||
// need to research how to get the data from WebJS
|
||||
// @ts-ignore
|
||||
@@ -512,17 +557,23 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
}
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
const chat: Chat = await this.whatsapp.getChatById(
|
||||
this.ensureSuffix(request.chatId),
|
||||
);
|
||||
await chat.sendSeen();
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
const chat: Chat = await this.whatsapp.getChatById(
|
||||
this.ensureSuffix(request.chatId),
|
||||
);
|
||||
await chat.sendStateTyping();
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
const chat: Chat = await this.whatsapp.getChatById(
|
||||
this.ensureSuffix(request.chatId),
|
||||
);
|
||||
await chat.clearState();
|
||||
}
|
||||
|
||||
@@ -658,7 +709,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
}
|
||||
|
||||
async deleteChat(chatId) {
|
||||
const chat = await this.whatsapp.getChatById(chatId);
|
||||
const chat = await this.whatsapp.getChatById(this.ensureSuffix(chatId));
|
||||
return chat.delete();
|
||||
}
|
||||
|
||||
@@ -922,6 +973,25 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
/**
|
||||
* Channels methods
|
||||
*/
|
||||
public searchChannelsByView(
|
||||
query: ChannelSearchByView,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
public searchChannelsByText(
|
||||
query: ChannelSearchByText,
|
||||
): Promise<ChannelListResult> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
public async previewChannelMessages(
|
||||
inviteCode: string,
|
||||
query: PreviewChannelMessages,
|
||||
): Promise<ChannelMessage[]> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
protected ChatToChannel(chat: WEBJSChannel): Channel {
|
||||
// @ts-ignore
|
||||
const metadata = chat.channelMetadata;
|
||||
@@ -938,6 +1008,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
picture: null,
|
||||
verified: metadata.verified,
|
||||
role: role,
|
||||
subscribersCount: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -955,6 +1026,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
picture: metadata.pictureUrl,
|
||||
verified: metadata.isVerified,
|
||||
role: role,
|
||||
subscribersCount: metadata.subscribersCount,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -966,6 +1038,10 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
channels = channels.filter((channel) => channel.role === query.role);
|
||||
}
|
||||
|
||||
// Exclude GUEST, browser saves the data
|
||||
// when we search channels or getting messages
|
||||
channels = channels.filter((channel) => channel.role === 'GUEST');
|
||||
|
||||
const promises = channels.map(async (channel) =>
|
||||
this.whatsapp.getProfilePicUrl(channel.id),
|
||||
);
|
||||
@@ -1054,7 +1130,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
* Status methods
|
||||
*/
|
||||
protected checkStatusRequest(request: StatusRequest) {
|
||||
if (request.contacts?.length > 0) {
|
||||
if (request.contacts && request.contacts?.length > 0) {
|
||||
const msg =
|
||||
"WEBJS doesn't accept 'contacts'. Remove the field to send status to all contacts.";
|
||||
throw new UnprocessableEntityException(msg);
|
||||
@@ -1164,10 +1240,52 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
//
|
||||
// Groups
|
||||
//
|
||||
const groupJoin$ = fromEvent(this.whatsapp, Events.GROUP_JOIN);
|
||||
this.events2.get(WAHAEvents.GROUP_JOIN).switch(groupJoin$);
|
||||
const groupLeave$ = fromEvent(this.whatsapp, Events.GROUP_LEAVE);
|
||||
this.events2.get(WAHAEvents.GROUP_LEAVE).switch(groupLeave$);
|
||||
const groupJoin$ = fromEvent<GroupNotification>(
|
||||
this.whatsapp,
|
||||
Events.GROUP_JOIN,
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_JOIN).switch(groupJoin$); // v1
|
||||
const groupV2Join$ = groupJoin$.pipe(
|
||||
mergeMap((evt) =>
|
||||
ToGroupV2JoinEvent(this.whatsapp, this.getSessionMeInfo().id, evt),
|
||||
),
|
||||
filter(Boolean),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_JOIN).switch(groupV2Join$);
|
||||
|
||||
const groupLeave$ = fromEvent<GroupNotification>(
|
||||
this.whatsapp,
|
||||
Events.GROUP_LEAVE,
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_LEAVE).switch(groupLeave$); // v1
|
||||
const groupV2Leave$ = groupLeave$.pipe(
|
||||
map((evt) => ToGroupV2LeaveEvent(this.getSessionMeInfo().id, evt)),
|
||||
filter(Boolean),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_LEAVE).switch(groupV2Leave$);
|
||||
|
||||
const groupAdminChanged$ = fromEvent(
|
||||
this.whatsapp,
|
||||
Events.GROUP_ADMIN_CHANGED,
|
||||
);
|
||||
const groupV2Participants = merge(
|
||||
groupJoin$,
|
||||
groupLeave$,
|
||||
groupAdminChanged$,
|
||||
).pipe(map(ToGroupV2ParticipantsEvent), filter(Boolean));
|
||||
this.events2
|
||||
.get(WAHAEvents.GROUP_V2_PARTICIPANTS)
|
||||
.switch(groupV2Participants);
|
||||
|
||||
const groupUpdate$ = fromEvent<GroupNotification>(
|
||||
this.whatsapp,
|
||||
Events.GROUP_UPDATE,
|
||||
);
|
||||
const groupV2Update$ = groupUpdate$.pipe(
|
||||
mergeMap((evt) => ToGroupV2UpdateEvent(this.whatsapp, evt)),
|
||||
filter(Boolean),
|
||||
);
|
||||
this.events2.get(WAHAEvents.GROUP_V2_UPDATE).switch(groupV2Update$);
|
||||
|
||||
//
|
||||
// Chats
|
||||
@@ -1211,7 +1329,10 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
this.events2.get(WAHAEvents.CALL_RECEIVED).switch(calls$);
|
||||
}
|
||||
|
||||
private async processIncomingMessage(message: Message, downloadMedia = true) {
|
||||
protected async processIncomingMessage(
|
||||
message: Message,
|
||||
downloadMedia = true,
|
||||
) {
|
||||
if (downloadMedia) {
|
||||
try {
|
||||
message = await this.downloadMedia(message);
|
||||
@@ -1250,9 +1371,9 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
body: message.body,
|
||||
// Media
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.media),
|
||||
hasMedia: Boolean(message.hasMedia),
|
||||
// @ts-ignore
|
||||
media: message.media,
|
||||
media: message.media || null,
|
||||
// @ts-ignore
|
||||
mediaUrl: message.media?.url,
|
||||
// @ts-ignore
|
||||
@@ -1267,7 +1388,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
|
||||
protected extractReplyTo(message: Message): ReplyToMessage | null {
|
||||
// @ts-ignore
|
||||
const quotedMsg = message.rawData.quotedMsg;
|
||||
const quotedMsg = message.rawData?.quotedMsg;
|
||||
if (!quotedMsg) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AvailableInPlusVersion } from '@waha/core/exceptions';
|
||||
import {
|
||||
ChannelCategory,
|
||||
ChannelCountry,
|
||||
ChannelView,
|
||||
} from '@waha/structures/channels.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ChannelsInfoServiceCore {
|
||||
async getCountries(): Promise<ChannelCountry[]> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
async getCategories(): Promise<ChannelCategory[]> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
async getViews(): Promise<ChannelView[]> {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,11 @@ function splitAt(str: string, index) {
|
||||
return [fst.join(''), snd.join('')];
|
||||
}
|
||||
|
||||
export function sortObjectByValues(obj: any) {
|
||||
return Object.fromEntries(
|
||||
// @ts-ignore
|
||||
Object.entries(obj).sort(([, v1], [, v2]) => v2 - v1),
|
||||
);
|
||||
}
|
||||
|
||||
export { flipObject, parseBool, splitAt };
|
||||
+16
-6
@@ -1,5 +1,6 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { WsAdapter } from '@nestjs/platform-ws';
|
||||
import { WAHA_WEBHOOKS } from '@waha/structures/webhooks';
|
||||
import {
|
||||
getNestJSLogLevels,
|
||||
getPinoLogLevel,
|
||||
@@ -15,7 +16,6 @@ import { WhatsappConfigService } from './config.service';
|
||||
import { AppModuleCore } from './core/app.module.core';
|
||||
import { SwaggerConfiguratorCore } from './core/SwaggerConfiguratorCore';
|
||||
import { AllExceptionsFilter } from './nestjs/AllExceptionsFilter';
|
||||
import { WAHA_WEBHOOKS } from './structures/webhooks.dto';
|
||||
import { getWAHAVersion, VERSION, WAHAVersion } from './version';
|
||||
|
||||
const logger: Logger = pino({
|
||||
@@ -23,12 +23,22 @@ const logger: Logger = pino({
|
||||
transport: getPinoTransport(),
|
||||
}).child({ name: 'Bootstrap' });
|
||||
|
||||
logger.info('NODE - Catching unhandled rejection enabled');
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
||||
// @ts-ignore
|
||||
logger.error(reason.stack);
|
||||
process.on('uncaughtException', (err) => {
|
||||
logger.error('Uncaught Exception:', err);
|
||||
if (err instanceof Error) {
|
||||
logger.error(err.stack);
|
||||
}
|
||||
});
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
logger.error('Unhandled Rejection at:', promise);
|
||||
if (reason instanceof Error) {
|
||||
logger.error(reason.stack);
|
||||
} else {
|
||||
logger.error('Unhandled rejection reason:', reason);
|
||||
}
|
||||
});
|
||||
logger.info('NODE - Catching unhandled rejections and exceptions enabled');
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
logger.info('SIGINT received');
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ export class WebsocketHeartbeatJob {
|
||||
this.logger.debug(
|
||||
`Terminating client connection due to heartbeat timeout, ${client.id}`,
|
||||
);
|
||||
return client.terminate();
|
||||
client.terminate();
|
||||
}
|
||||
|
||||
client.isAlive = false;
|
||||
|
||||
@@ -35,14 +35,6 @@ export class RequestCodeRequest {
|
||||
localeCountry: string;
|
||||
}
|
||||
|
||||
export class OTPRequest {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export class CaptchaBody {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export class PairingCodeResponse {
|
||||
code: string;
|
||||
}
|
||||
@@ -18,3 +18,7 @@ export class SessionQuery {
|
||||
export class SessionBaseRequest {
|
||||
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
}
|
||||
|
||||
export class Result {
|
||||
success: boolean = true;
|
||||
}
|
||||
@@ -1,5 +1,17 @@
|
||||
import { ApiParam, ApiProperty, getSchemaPath } from '@nestjs/swagger';
|
||||
import { BooleanString } from '@waha/nestjs/validation/BooleanString';
|
||||
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
|
||||
import { WAMessage } from '@waha/structures/responses.dto';
|
||||
import { Transform, Type } from 'class-transformer';
|
||||
import {
|
||||
ArrayMinSize,
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateChannelRequest {
|
||||
@ApiProperty({
|
||||
@@ -38,7 +50,7 @@ export class ListChannelsQuery {
|
||||
role?: ChannelRoleFilter;
|
||||
}
|
||||
|
||||
export class Channel {
|
||||
class ChannelBase {
|
||||
@ApiProperty({
|
||||
description: 'Newsletter id',
|
||||
example: '123123123123@newsletter',
|
||||
@@ -73,9 +85,15 @@ export class Channel {
|
||||
|
||||
verified: boolean;
|
||||
|
||||
subscribersCount: number;
|
||||
}
|
||||
|
||||
export class Channel extends ChannelBase {
|
||||
role: ChannelRole;
|
||||
}
|
||||
|
||||
export class ChannelPublicInfo extends ChannelBase {}
|
||||
|
||||
export const NewsletterIdApiParam = ApiParam({
|
||||
name: 'id',
|
||||
required: true,
|
||||
@@ -96,3 +114,86 @@ export const NewsletterIdOrInviteCodeApiParam = ApiParam({
|
||||
description:
|
||||
'WhatsApp Channel ID or invite code from invite link https://www.whatsapp.com/channel/11111',
|
||||
});
|
||||
|
||||
export class ChannelCountry {
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ChannelCategory {
|
||||
value: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ChannelView {
|
||||
value: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ChannelSearch {
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
limit: number = 50;
|
||||
|
||||
@IsString()
|
||||
startCursor: string = '';
|
||||
}
|
||||
|
||||
export class ChannelSearchByView extends ChannelSearch {
|
||||
@IsString()
|
||||
view: string = 'RECOMMENDED';
|
||||
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
@ArrayMinSize(1)
|
||||
countries: string[] = ['US'];
|
||||
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
categories: string[] = [];
|
||||
}
|
||||
|
||||
export class ChannelSearchByText extends ChannelSearch {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
text: string = 'Donald Trump';
|
||||
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
categories: string[] = [];
|
||||
}
|
||||
|
||||
export class ChannelPagination {
|
||||
startCursor: string | null;
|
||||
endCursor: string | null;
|
||||
hasNextPage: boolean;
|
||||
hasPreviousPage: boolean;
|
||||
}
|
||||
|
||||
export class ChannelListResult {
|
||||
page: ChannelPagination;
|
||||
channels: ChannelPublicInfo[];
|
||||
}
|
||||
|
||||
export class ChannelMessage {
|
||||
message: WAMessage;
|
||||
|
||||
@ApiProperty({
|
||||
example: { '👍': 10, '❤️': 5 },
|
||||
type: Object,
|
||||
additionalProperties: { type: 'number' },
|
||||
})
|
||||
reactions: { [emoji: string]: number };
|
||||
|
||||
viewCount: number;
|
||||
}
|
||||
|
||||
export class PreviewChannelMessages {
|
||||
@Transform(BooleanString)
|
||||
@IsBoolean()
|
||||
downloadMedia: boolean = false;
|
||||
|
||||
@IsNumber()
|
||||
@Type(() => Number)
|
||||
limit: number = 100;
|
||||
}
|
||||
@@ -11,6 +11,10 @@ export enum WAHAEvents {
|
||||
STATE_CHANGE = 'state.change',
|
||||
GROUP_JOIN = 'group.join',
|
||||
GROUP_LEAVE = 'group.leave',
|
||||
GROUP_V2_JOIN = 'group.v2.join',
|
||||
GROUP_V2_LEAVE = 'group.v2.leave',
|
||||
GROUP_V2_UPDATE = 'group.v2.update',
|
||||
GROUP_V2_PARTICIPANTS = 'group.v2.participants',
|
||||
PRESENCE_UPDATE = 'presence.update',
|
||||
POLL_VOTE = 'poll.vote',
|
||||
POLL_VOTE_FAILED = 'poll.vote.failed',
|
||||
|
||||
@@ -88,3 +88,69 @@ export class GroupsPaginationParams extends PaginationParams {
|
||||
@IsEnum(GroupSortField)
|
||||
sortBy?: string;
|
||||
}
|
||||
|
||||
export enum GroupParticipantRole {
|
||||
LEFT = 'left',
|
||||
PARTICIPANT = 'participant',
|
||||
ADMIN = 'admin',
|
||||
SUPERADMIN = 'superadmin',
|
||||
}
|
||||
|
||||
export class GroupParticipant {
|
||||
@ApiProperty({
|
||||
example: '123456789@c.us',
|
||||
})
|
||||
id: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: GroupParticipantRole.PARTICIPANT,
|
||||
})
|
||||
role: GroupParticipantRole;
|
||||
}
|
||||
|
||||
export class GroupId {
|
||||
@ApiProperty({
|
||||
example: '123456789@g.us',
|
||||
})
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class GroupInfo {
|
||||
@ApiProperty({
|
||||
example: '123456789@g.us',
|
||||
})
|
||||
id: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'Group Name',
|
||||
})
|
||||
subject: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'Group Description',
|
||||
})
|
||||
description: string;
|
||||
|
||||
participants: GroupParticipant[];
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Invite URL',
|
||||
example: 'https://chat.whatsapp.com/1234567890abcdef',
|
||||
})
|
||||
invite?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Members can add new members',
|
||||
})
|
||||
membersCanAddNewMember: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Members can send messages to the group',
|
||||
})
|
||||
membersCanSendMessages: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Admin approval required for new members',
|
||||
})
|
||||
newMembersApprovalRequired: boolean;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
import { GroupId, GroupInfo, GroupParticipant } from './groups.dto';
|
||||
|
||||
/**
|
||||
* Happens when you join or are added to a group.
|
||||
*/
|
||||
export class GroupV2JoinEvent {
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp',
|
||||
example: 1666943582,
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
group: GroupInfo;
|
||||
|
||||
_data: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Happens when you leave or are removed from a group.
|
||||
*/
|
||||
export class GroupV2LeaveEvent {
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp',
|
||||
example: 1666943582,
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
group: GroupId;
|
||||
|
||||
_data: any;
|
||||
}
|
||||
|
||||
export class GroupV2UpdateEvent {
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp',
|
||||
example: 1666943582,
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
group: Partial<GroupInfo>;
|
||||
|
||||
_data: any;
|
||||
}
|
||||
|
||||
export enum GroupParticipantType {
|
||||
JOIN = 'join',
|
||||
LEAVE = 'leave',
|
||||
PROMOTE = 'promote',
|
||||
DEMOTE = 'demote',
|
||||
}
|
||||
|
||||
export class GroupV2ParticipantsEvent {
|
||||
group: GroupId;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Type of the event',
|
||||
})
|
||||
type: GroupParticipantType;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp',
|
||||
example: 1666943582,
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
participants: GroupParticipant[];
|
||||
|
||||
_data: any;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { WAHAEvents } from '@waha/structures/enums.dto';
|
||||
import {
|
||||
GroupV2JoinEvent,
|
||||
GroupV2LeaveEvent,
|
||||
GroupV2ParticipantsEvent,
|
||||
GroupV2UpdateEvent,
|
||||
} from '@waha/structures/groups.events.dto';
|
||||
import { WAHAWebhook } from '@waha/structures/webhooks.dto';
|
||||
|
||||
export class WebhookGroupV2Join extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'When you joined or were added to a group',
|
||||
})
|
||||
event = WAHAEvents.GROUP_V2_JOIN;
|
||||
|
||||
payload: GroupV2JoinEvent;
|
||||
}
|
||||
|
||||
export class WebhookGroupV2Leave extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'When you left or were removed from a group',
|
||||
})
|
||||
event = WAHAEvents.GROUP_V2_LEAVE;
|
||||
|
||||
payload: GroupV2LeaveEvent;
|
||||
}
|
||||
|
||||
export class WebhookGroupV2Update extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'When group info is updated',
|
||||
})
|
||||
event = WAHAEvents.GROUP_V2_UPDATE;
|
||||
|
||||
payload: GroupV2UpdateEvent;
|
||||
}
|
||||
|
||||
export class WebhookGroupV2Participants extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'When participants changed - join, leave, promote to admin',
|
||||
})
|
||||
event = WAHAEvents.GROUP_V2_PARTICIPANTS;
|
||||
|
||||
payload: GroupV2ParticipantsEvent;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
|
||||
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
|
||||
import { ChatIdProperty } from '@waha/structures/properties.dto';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class MyProfile {
|
||||
@ChatIdProperty()
|
||||
id: string;
|
||||
|
||||
name: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'https://example.com/picture.jpg',
|
||||
})
|
||||
picture: string | null;
|
||||
}
|
||||
|
||||
export class ProfileNameRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
example: 'My New Name',
|
||||
})
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ProfileStatusRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
example: '🎉 Hey there! I am using WhatsApp 🎉',
|
||||
})
|
||||
status: string;
|
||||
}
|
||||
|
||||
@ApiExtraModels(RemoteFile, BinaryFile)
|
||||
export class ProfilePictureRequest {
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(RemoteFile) },
|
||||
{ $ref: getSchemaPath(BinaryFile) },
|
||||
],
|
||||
})
|
||||
file: BinaryFile | RemoteFile;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export interface StatusRequest {
|
||||
export class TextStatus {
|
||||
text: string = 'Have a look! https://github.com/';
|
||||
backgroundColor: string = '#38b42f';
|
||||
font: number = 1;
|
||||
font: number = 0;
|
||||
|
||||
@ContactsProperty
|
||||
contacts?: string[];
|
||||
|
||||
@@ -91,6 +91,7 @@ export class PollVotePayload {
|
||||
export class WAMessageRevokedBody {
|
||||
after?: WAMessage;
|
||||
before?: WAMessage;
|
||||
_data?: any;
|
||||
}
|
||||
|
||||
export class WASessionStatusBody {
|
||||
@@ -148,14 +149,14 @@ export class WAHAWebhookSessionStatus extends WAHAWebhook {
|
||||
payload: WASessionStatusBody;
|
||||
}
|
||||
|
||||
class WAHAWebhookMessage extends WAHAWebhook {
|
||||
export class WAHAWebhookMessage extends WAHAWebhook {
|
||||
@ApiProperty({ description: 'Incoming message.' })
|
||||
event = WAHAEvents.MESSAGE;
|
||||
|
||||
payload: WAMessage;
|
||||
}
|
||||
|
||||
class WAHAWebhookMessageReaction extends WAHAWebhook {
|
||||
export class WAHAWebhookMessageReaction extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'The event is triggered when a user reacts or removes a reaction.',
|
||||
@@ -165,7 +166,7 @@ class WAHAWebhookMessageReaction extends WAHAWebhook {
|
||||
payload: WAMessageReaction;
|
||||
}
|
||||
|
||||
class WAHAWebhookMessageAny extends WAHAWebhook {
|
||||
export class WAHAWebhookMessageAny extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'Fired on all message creations, including your own.',
|
||||
})
|
||||
@@ -174,7 +175,7 @@ class WAHAWebhookMessageAny extends WAHAWebhook {
|
||||
payload: WAMessage;
|
||||
}
|
||||
|
||||
class WAHAWebhookMessageAck extends WAHAWebhook {
|
||||
export class WAHAWebhookMessageAck extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Receive events when server or recipient gets the message, read or played it.',
|
||||
@@ -184,7 +185,7 @@ class WAHAWebhookMessageAck extends WAHAWebhook {
|
||||
payload: WAMessageAckBody;
|
||||
}
|
||||
|
||||
class WAHAWebhookMessageRevoked extends WAHAWebhook {
|
||||
export class WAHAWebhookMessageRevoked extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'The event is triggered when a user, whether it be you or any other participant, ' +
|
||||
@@ -195,34 +196,37 @@ class WAHAWebhookMessageRevoked extends WAHAWebhook {
|
||||
payload: WAMessageRevokedBody;
|
||||
}
|
||||
|
||||
class WAHAWebhookStateChange extends WAHAWebhook {
|
||||
export class WAHAWebhookStateChange extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'It’s an internal engine’s state, not session status.',
|
||||
deprecated: true,
|
||||
})
|
||||
event = WAHAEvents.STATE_CHANGE;
|
||||
|
||||
payload: any;
|
||||
}
|
||||
|
||||
class WAHAWebhookGroupJoin extends WAHAWebhook {
|
||||
export class WAHAWebhookGroupJoin extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'Some one join a group.',
|
||||
deprecated: true,
|
||||
})
|
||||
event = WAHAEvents.GROUP_JOIN;
|
||||
|
||||
payload: any;
|
||||
}
|
||||
|
||||
class WAHAWebhookGroupLeave extends WAHAWebhook {
|
||||
export class WAHAWebhookGroupLeave extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'Some one left a group.',
|
||||
deprecated: true,
|
||||
})
|
||||
event = WAHAEvents.GROUP_LEAVE;
|
||||
|
||||
payload: any;
|
||||
}
|
||||
|
||||
class WAHAWebhookPresenceUpdate extends WAHAWebhook {
|
||||
export class WAHAWebhookPresenceUpdate extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'The most recent presence information for a chat.',
|
||||
})
|
||||
@@ -231,7 +235,7 @@ class WAHAWebhookPresenceUpdate extends WAHAWebhook {
|
||||
payload: WAHAChatPresences;
|
||||
}
|
||||
|
||||
class WAHAWebhookPollVote extends WAHAWebhook {
|
||||
export class WAHAWebhookPollVote extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'With this event, you receive new votes for the poll sent.',
|
||||
})
|
||||
@@ -240,7 +244,7 @@ class WAHAWebhookPollVote extends WAHAWebhook {
|
||||
payload: PollVotePayload;
|
||||
}
|
||||
|
||||
class WAHAWebhookPollVoteFailed extends WAHAWebhook {
|
||||
export class WAHAWebhookPollVoteFailed extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'There may be cases when it fails to decrypt a vote from the user. ' +
|
||||
@@ -251,7 +255,7 @@ class WAHAWebhookPollVoteFailed extends WAHAWebhook {
|
||||
payload: PollVotePayload;
|
||||
}
|
||||
|
||||
class WAHAWebhookChatArchive extends WAHAWebhook {
|
||||
export class WAHAWebhookChatArchive extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'The event is triggered when the chat is archived or unarchived',
|
||||
@@ -261,7 +265,7 @@ class WAHAWebhookChatArchive extends WAHAWebhook {
|
||||
payload: ChatArchiveEvent;
|
||||
}
|
||||
|
||||
class WAHAWebhookCallReceived extends WAHAWebhook {
|
||||
export class WAHAWebhookCallReceived extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'The event is triggered when the call is received by the user.',
|
||||
@@ -271,7 +275,7 @@ class WAHAWebhookCallReceived extends WAHAWebhook {
|
||||
payload: CallData;
|
||||
}
|
||||
|
||||
class WAHAWebhookCallAccepted extends WAHAWebhook {
|
||||
export class WAHAWebhookCallAccepted extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'The event is triggered when the call is accepted by the user.',
|
||||
@@ -281,7 +285,7 @@ class WAHAWebhookCallAccepted extends WAHAWebhook {
|
||||
payload: CallData;
|
||||
}
|
||||
|
||||
class WAHAWebhookCallRejected extends WAHAWebhook {
|
||||
export class WAHAWebhookCallRejected extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description:
|
||||
'The event is triggered when the call is rejected by the user.',
|
||||
@@ -291,7 +295,7 @@ class WAHAWebhookCallRejected extends WAHAWebhook {
|
||||
payload: CallData;
|
||||
}
|
||||
|
||||
class WAHAWebhookLabelUpsert extends WAHAWebhook {
|
||||
export class WAHAWebhookLabelUpsert extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'The event is triggered when a label is created or updated',
|
||||
})
|
||||
@@ -300,7 +304,7 @@ class WAHAWebhookLabelUpsert extends WAHAWebhook {
|
||||
payload: Label;
|
||||
}
|
||||
|
||||
class WAHAWebhookLabelDeleted extends WAHAWebhook {
|
||||
export class WAHAWebhookLabelDeleted extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'The event is triggered when a label is deleted',
|
||||
})
|
||||
@@ -309,7 +313,7 @@ class WAHAWebhookLabelDeleted extends WAHAWebhook {
|
||||
payload: Label;
|
||||
}
|
||||
|
||||
class WAHAWebhookLabelChatAdded extends WAHAWebhook {
|
||||
export class WAHAWebhookLabelChatAdded extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'The event is triggered when a label is added to a chat',
|
||||
})
|
||||
@@ -318,7 +322,7 @@ class WAHAWebhookLabelChatAdded extends WAHAWebhook {
|
||||
payload: LabelChatAssociation;
|
||||
}
|
||||
|
||||
class WAHAWebhookLabelChatDeleted extends WAHAWebhook {
|
||||
export class WAHAWebhookLabelChatDeleted extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'The event is triggered when a label is deleted from a chat',
|
||||
})
|
||||
@@ -332,7 +336,7 @@ export class EnginePayload {
|
||||
data: any;
|
||||
}
|
||||
|
||||
class WAHAWebhookEngineEvent extends WAHAWebhook {
|
||||
export class WAHAWebhookEngineEvent extends WAHAWebhook {
|
||||
@ApiProperty({
|
||||
description: 'Internal engine event.',
|
||||
})
|
||||
@@ -340,28 +344,3 @@ class WAHAWebhookEngineEvent extends WAHAWebhook {
|
||||
|
||||
payload: EnginePayload;
|
||||
}
|
||||
|
||||
const WAHA_WEBHOOKS = [
|
||||
WAHAWebhookSessionStatus,
|
||||
WAHAWebhookMessage,
|
||||
WAHAWebhookMessageReaction,
|
||||
WAHAWebhookMessageAny,
|
||||
WAHAWebhookMessageAck,
|
||||
WAHAWebhookMessageRevoked,
|
||||
WAHAWebhookStateChange,
|
||||
WAHAWebhookGroupJoin,
|
||||
WAHAWebhookGroupLeave,
|
||||
WAHAWebhookPresenceUpdate,
|
||||
WAHAWebhookPollVote,
|
||||
WAHAWebhookPollVoteFailed,
|
||||
WAHAWebhookChatArchive,
|
||||
WAHAWebhookCallReceived,
|
||||
WAHAWebhookCallAccepted,
|
||||
WAHAWebhookCallRejected,
|
||||
WAHAWebhookLabelUpsert,
|
||||
WAHAWebhookLabelDeleted,
|
||||
WAHAWebhookLabelChatAdded,
|
||||
WAHAWebhookLabelChatDeleted,
|
||||
WAHAWebhookEngineEvent,
|
||||
];
|
||||
export { WAHA_WEBHOOKS };
|
||||
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
WebhookGroupV2Join,
|
||||
WebhookGroupV2Leave,
|
||||
WebhookGroupV2Participants,
|
||||
WebhookGroupV2Update,
|
||||
} from '@waha/structures/groups.webhooks.dto';
|
||||
import {
|
||||
WAHAWebhookCallAccepted,
|
||||
WAHAWebhookCallReceived,
|
||||
WAHAWebhookCallRejected,
|
||||
WAHAWebhookChatArchive,
|
||||
WAHAWebhookEngineEvent,
|
||||
WAHAWebhookGroupJoin,
|
||||
WAHAWebhookGroupLeave,
|
||||
WAHAWebhookLabelChatAdded,
|
||||
WAHAWebhookLabelChatDeleted,
|
||||
WAHAWebhookLabelDeleted,
|
||||
WAHAWebhookLabelUpsert,
|
||||
WAHAWebhookMessage,
|
||||
WAHAWebhookMessageAck,
|
||||
WAHAWebhookMessageAny,
|
||||
WAHAWebhookMessageReaction,
|
||||
WAHAWebhookMessageRevoked,
|
||||
WAHAWebhookPollVote,
|
||||
WAHAWebhookPollVoteFailed,
|
||||
WAHAWebhookPresenceUpdate,
|
||||
WAHAWebhookSessionStatus,
|
||||
WAHAWebhookStateChange,
|
||||
} from '@waha/structures/webhooks.dto';
|
||||
|
||||
const WAHA_WEBHOOKS = [
|
||||
WAHAWebhookSessionStatus,
|
||||
WAHAWebhookMessage,
|
||||
WAHAWebhookMessageReaction,
|
||||
WAHAWebhookMessageAny,
|
||||
WAHAWebhookMessageAck,
|
||||
WAHAWebhookMessageRevoked,
|
||||
WebhookGroupV2Join,
|
||||
WebhookGroupV2Leave,
|
||||
WebhookGroupV2Update,
|
||||
WebhookGroupV2Participants,
|
||||
WAHAWebhookPresenceUpdate,
|
||||
WAHAWebhookPollVote,
|
||||
WAHAWebhookPollVoteFailed,
|
||||
WAHAWebhookChatArchive,
|
||||
WAHAWebhookCallReceived,
|
||||
WAHAWebhookCallAccepted,
|
||||
WAHAWebhookCallRejected,
|
||||
WAHAWebhookLabelUpsert,
|
||||
WAHAWebhookLabelDeleted,
|
||||
WAHAWebhookLabelChatAdded,
|
||||
WAHAWebhookLabelChatDeleted,
|
||||
WAHAWebhookEngineEvent,
|
||||
WAHAWebhookGroupJoin,
|
||||
WAHAWebhookGroupLeave,
|
||||
WAHAWebhookStateChange,
|
||||
];
|
||||
export { WAHA_WEBHOOKS };
|
||||
+1
-1
@@ -33,7 +33,7 @@ export function getEngineName(): string {
|
||||
}
|
||||
|
||||
export const VERSION: WAHAEnvironment = {
|
||||
version: '2025.1.4',
|
||||
version: '2025.2.6',
|
||||
engine: getEngineName(),
|
||||
tier: getWAHAVersion(),
|
||||
browser: getBrowserExecutablePath(),
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const axios = require('axios');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const yargs = require('yargs/yargs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
|
||||
// Parse CLI arguments
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option('number', {
|
||||
alias: 'n',
|
||||
type: 'number',
|
||||
description: 'Number of messages to send',
|
||||
default: 10,
|
||||
})
|
||||
.option('chat-id', {
|
||||
alias: 'to',
|
||||
type: 'number',
|
||||
description: 'Chat ID to send messages to',
|
||||
demandOption: true,
|
||||
})
|
||||
.option('session', {
|
||||
type: 'string',
|
||||
description: 'Session ID to use',
|
||||
demandOption: true,
|
||||
})
|
||||
.option('api-key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'API key for authentication',
|
||||
demandOption: true,
|
||||
})
|
||||
.help().argv;
|
||||
|
||||
const sendTextMessage = async (session, numMessages, chatId, apiKey) => {
|
||||
const url = 'http://localhost:3000/api/sendText/';
|
||||
for (let i = 1; i <= numMessages; i++) {
|
||||
console.log(`Sending message ${i}`);
|
||||
const response = await axios.post(
|
||||
url,
|
||||
{
|
||||
chatId: chatId.toString(),
|
||||
session: session,
|
||||
text: `Message - ${i}`,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Api-Key': apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
);
|
||||
console.log(`Message ${i} sent successfully:`, response.data);
|
||||
}
|
||||
};
|
||||
|
||||
// Run the script
|
||||
sendTextMessage(argv.session, argv.number, argv['chat-id'], argv['api-key']);
|
||||
@@ -0,0 +1,56 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const axios = require('axios');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const yargs = require('yargs/yargs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
|
||||
// Parse CLI arguments
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option('sessions', {
|
||||
alias: 'n',
|
||||
type: 'number',
|
||||
description: 'Number of sessions to create',
|
||||
default: 10,
|
||||
})
|
||||
.option('api-key', {
|
||||
alias: 'k',
|
||||
type: 'string',
|
||||
description: 'API key for authentication',
|
||||
demandOption: true,
|
||||
})
|
||||
.help().argv;
|
||||
|
||||
const createSessions = async (numSessions, apiKey) => {
|
||||
const url = 'http://localhost:3000/api/sessions/';
|
||||
|
||||
for (let i = 1; i <= numSessions; i++) {
|
||||
try {
|
||||
console.log(`Creating session ${i}`);
|
||||
const response = await axios.post(
|
||||
url,
|
||||
{
|
||||
name: '',
|
||||
config: {
|
||||
metadata: {},
|
||||
webhooks: [],
|
||||
},
|
||||
start: true,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Api-Key': apiKey,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
);
|
||||
console.log(`Session ${i} created successfully:`, response.data);
|
||||
} catch (error) {
|
||||
console.error(`Error creating session ${i}:`, error.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Run the script
|
||||
createSessions(argv.sessions, argv['api-key']);
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "scripts/*.js"]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"waha": {
|
||||
"gows": {
|
||||
"repo": "devlikeapro/gows",
|
||||
"ref": "8b31d6b88166e0962ca47a3dfbd256a42f09dbc1"
|
||||
},
|
||||
"dashboard": {
|
||||
"repo": "devlikeapro/dashboard",
|
||||
"ref": "d6cd941f8d7621f401305e03ad2c1db8dc0a64f0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,13 @@ __metadata:
|
||||
version: 6
|
||||
cacheKey: 8
|
||||
|
||||
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-678":
|
||||
version: 6.7.8
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=04738f528321857efe837e3f93c73059878ecdcb"
|
||||
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-6712":
|
||||
version: 6.7.12
|
||||
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=dcc5d0ea0827c0d57ceda4f94b9cdb260760b77e"
|
||||
dependencies:
|
||||
"@adiwajshing/keyed-db": ^0.2.4
|
||||
"@hapi/boom": ^9.1.3
|
||||
"@whiskeysockets/eslint-config": "github:whiskeysockets/eslint-config"
|
||||
async-lock: ^1.4.1
|
||||
audio-decode: ^2.1.3
|
||||
axios: ^1.6.0
|
||||
@@ -39,7 +40,7 @@ __metadata:
|
||||
optional: true
|
||||
sharp:
|
||||
optional: true
|
||||
checksum: 0f7b2031eeb25137c65aee3151028f7a8637cfed0763c7426817415ec818ca71f55267b9de88511905bd266f4006301a26206dac9bdb1821d13f1a0cbf075e32
|
||||
checksum: 24e16d0b11dbb83a562e333fcc11f9489d4f3c6735c12f726eead983dd3bbc0f4dbce9c486d849b26ddcb0e2be68972d205d21837aabfcb42ebd8b115958f053
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1242,6 +1243,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint-community/eslint-utils@npm:^4.4.0":
|
||||
version: 4.4.1
|
||||
resolution: "@eslint-community/eslint-utils@npm:4.4.1"
|
||||
dependencies:
|
||||
eslint-visitor-keys: ^3.4.3
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||
checksum: a7ffc838eb6a9ef594cda348458ccf38f34439ac77dc090fa1c120024bcd4eb911dfd74d5ef44d42063e7949fa7c5123ce714a015c4abb917d4124be1bd32bfe
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint-community/regexpp@npm:^4.10.0":
|
||||
version: 4.12.1
|
||||
resolution: "@eslint-community/regexpp@npm:4.12.1"
|
||||
checksum: 0d628680e204bc316d545b4993d3658427ca404ae646ce541fcc65306b8c712c340e5e573e30fb9f85f4855c0c5f6dca9868931f2fcced06417fbe1a0c6cd2d6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grpc/grpc-js@npm:^1.12.4":
|
||||
version: 1.12.4
|
||||
resolution: "@grpc/grpc-js@npm:1.12.4"
|
||||
@@ -3453,6 +3472,29 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:^7.15.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:7.18.0"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": ^4.10.0
|
||||
"@typescript-eslint/scope-manager": 7.18.0
|
||||
"@typescript-eslint/type-utils": 7.18.0
|
||||
"@typescript-eslint/utils": 7.18.0
|
||||
"@typescript-eslint/visitor-keys": 7.18.0
|
||||
graphemer: ^1.4.0
|
||||
ignore: ^5.3.1
|
||||
natural-compare: ^1.4.0
|
||||
ts-api-utils: ^1.3.0
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^7.0.0
|
||||
eslint: ^8.56.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: dfcf150628ca2d4ccdfc20b46b0eae075c2f16ef5e70d9d2f0d746acf4c69a09f962b93befee01a529f14bbeb3e817b5aba287d7dd0edc23396bc5ed1f448c3d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/experimental-utils@npm:3.9.1":
|
||||
version: 3.9.1
|
||||
resolution: "@typescript-eslint/experimental-utils@npm:3.9.1"
|
||||
@@ -3486,6 +3528,51 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:^7.15.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/parser@npm:7.18.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": 7.18.0
|
||||
"@typescript-eslint/types": 7.18.0
|
||||
"@typescript-eslint/typescript-estree": 7.18.0
|
||||
"@typescript-eslint/visitor-keys": 7.18.0
|
||||
debug: ^4.3.4
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: 132b56ac3b2d90b588d61d005a70f6af322860974225b60201cbf45abf7304d67b7d8a6f0ade1c188ac4e339884e78d6dcd450417f1481998f9ddd155bab0801
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:7.18.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:7.18.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": 7.18.0
|
||||
"@typescript-eslint/visitor-keys": 7.18.0
|
||||
checksum: b982c6ac13d8c86bb3b949c6b4e465f3f60557c2ccf4cc229799827d462df56b9e4d3eaed7711d79b875422fc3d71ec1ebcb5195db72134d07c619e3c5506b57
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:7.18.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:7.18.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree": 7.18.0
|
||||
"@typescript-eslint/utils": 7.18.0
|
||||
debug: ^4.3.4
|
||||
ts-api-utils: ^1.3.0
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: 68fd5df5146c1a08cde20d59b4b919acab06a1b06194fe4f7ba1b928674880249890785fbbc97394142f2ef5cff5a7fba9b8a940449e7d5605306505348e38bc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:3.9.1":
|
||||
version: 3.9.1
|
||||
resolution: "@typescript-eslint/types@npm:3.9.1"
|
||||
@@ -3493,6 +3580,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:7.18.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/types@npm:7.18.0"
|
||||
checksum: 7df2750cd146a0acd2d843208d69f153b458e024bbe12aab9e441ad2c56f47de3ddfeb329c4d1ea0079e2577fea4b8c1c1ce15315a8d49044586b04fedfe7a4d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:3.9.1":
|
||||
version: 3.9.1
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:3.9.1"
|
||||
@@ -3512,6 +3606,39 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:7.18.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:7.18.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": 7.18.0
|
||||
"@typescript-eslint/visitor-keys": 7.18.0
|
||||
debug: ^4.3.4
|
||||
globby: ^11.1.0
|
||||
is-glob: ^4.0.3
|
||||
minimatch: ^9.0.4
|
||||
semver: ^7.6.0
|
||||
ts-api-utils: ^1.3.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
checksum: c82d22ec9654973944f779eb4eb94c52f4a6eafaccce2f0231ff7757313f3a0d0256c3252f6dfe6d43f57171d09656478acb49a629a9d0c193fb959bc3f36116
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:7.18.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/utils@npm:7.18.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": ^4.4.0
|
||||
"@typescript-eslint/scope-manager": 7.18.0
|
||||
"@typescript-eslint/types": 7.18.0
|
||||
"@typescript-eslint/typescript-estree": 7.18.0
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
checksum: 751dbc816dab8454b7dc6b26a56671dbec08e3f4ef94c2661ce1c0fc48fa2d05a64e03efe24cba2c22d03ba943cd3c5c7a5e1b7b03bbb446728aec1c640bd767
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:3.9.1":
|
||||
version: 3.9.1
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:3.9.1"
|
||||
@@ -3521,6 +3648,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:7.18.0":
|
||||
version: 7.18.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:7.18.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": 7.18.0
|
||||
eslint-visitor-keys: ^3.4.3
|
||||
checksum: 6e806a7cdb424c5498ea187a5a11d0fef7e4602a631be413e7d521e5aec1ab46ba00c76cfb18020adaa0a8c9802354a163bfa0deb74baa7d555526c7517bb158
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@wasm-audio-decoders/common@npm:9.0.4":
|
||||
version: 9.0.4
|
||||
resolution: "@wasm-audio-decoders/common@npm:9.0.4"
|
||||
@@ -3711,6 +3848,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@whiskeysockets/eslint-config@github:whiskeysockets/eslint-config":
|
||||
version: 1.0.0
|
||||
resolution: "@whiskeysockets/eslint-config@https://github.com/whiskeysockets/eslint-config.git#commit=326b55f2842668f4e11f471451c4e39819a0e1bf"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": ^7.15.0
|
||||
"@typescript-eslint/parser": ^7.15.0
|
||||
eslint-plugin-simple-import-sort: ^12.1.1
|
||||
peerDependencies:
|
||||
eslint: "*"
|
||||
typescript: ">=4"
|
||||
checksum: a1ae2c83b0b635cf4898b51a597cd9cabc0df3f5bd4f439a705a1f35877802e8f07836f3298d02b5543d41e07c266b348bd8c8458f83ed225d975e89618b0483
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@xtuc/ieee754@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "@xtuc/ieee754@npm:1.2.0"
|
||||
@@ -6236,6 +6387,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-simple-import-sort@npm:^12.1.1":
|
||||
version: 12.1.1
|
||||
resolution: "eslint-plugin-simple-import-sort@npm:12.1.1"
|
||||
peerDependencies:
|
||||
eslint: ">=5.0.0"
|
||||
checksum: 6d73e43ecf6221c1952e0cc820e6867e3e1fe973575e23d438d1d3de52284ceb2a01d31e20a76de11feb158bbba98f113150a676cc5526a8b3a5844d63ca37f8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.0.0, eslint-scope@npm:^5.1.0":
|
||||
version: 5.1.1
|
||||
resolution: "eslint-scope@npm:5.1.1"
|
||||
@@ -6262,6 +6422,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-visitor-keys@npm:^3.4.3":
|
||||
version: 3.4.3
|
||||
resolution: "eslint-visitor-keys@npm:3.4.3"
|
||||
checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint@npm:7.7.0":
|
||||
version: 7.7.0
|
||||
resolution: "eslint@npm:7.7.0"
|
||||
@@ -7174,7 +7341,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"globby@npm:^11.0.1":
|
||||
"globby@npm:^11.0.1, globby@npm:^11.1.0":
|
||||
version: 11.1.0
|
||||
resolution: "globby@npm:11.1.0"
|
||||
dependencies:
|
||||
@@ -7211,6 +7378,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphemer@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "graphemer@npm:1.4.0"
|
||||
checksum: bab8f0be9b568857c7bec9fda95a89f87b783546d02951c40c33f84d05bb7da3fd10f863a9beb901463669b6583173a8c8cc6d6b306ea2b9b9d5d3d943c3a673
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"grpc-tools@npm:^1.12.4":
|
||||
version: 1.12.4
|
||||
resolution: "grpc-tools@npm:1.12.4"
|
||||
@@ -7440,6 +7614,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ignore@npm:^5.3.1":
|
||||
version: 5.3.2
|
||||
resolution: "ignore@npm:5.3.2"
|
||||
checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "import-fresh@npm:3.3.0"
|
||||
@@ -12050,6 +12231,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-api-utils@npm:^1.3.0":
|
||||
version: 1.4.3
|
||||
resolution: "ts-api-utils@npm:1.4.3"
|
||||
peerDependencies:
|
||||
typescript: ">=4.2.0"
|
||||
checksum: ea00dee382d19066b2a3d8929f1089888b05fec797e32e7a7004938eda1dccf2e77274ee2afcd4166f53fab9b8d7ee90ebb225a3183f9ba8817d636f688a148d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-jest@npm:^29.1.3":
|
||||
version: 29.1.5
|
||||
resolution: "ts-jest@npm:29.1.5"
|
||||
@@ -12559,7 +12749,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "waha@workspace:."
|
||||
dependencies:
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-678"
|
||||
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-6712"
|
||||
"@adiwajshing/keyed-db": ^0.2.4
|
||||
"@aws-sdk/client-s3": ^3.633.0
|
||||
"@aws-sdk/s3-request-presigner": ^3.633.0
|
||||
@@ -12646,6 +12836,7 @@ __metadata:
|
||||
ulid: ^2.3.0
|
||||
whatsapp-web.js: "github:devlikeapro/whatsapp-web.js#fork-main-channels"
|
||||
write-file-atomic: ^6.0.0
|
||||
yargs: ^17.7.2
|
||||
dependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
@@ -12740,7 +12931,7 @@ __metadata:
|
||||
|
||||
"whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-channels":
|
||||
version: 1.26.0
|
||||
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=a8683b0d1a5b8025ac1e7deb3476042ceadb4c07"
|
||||
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=5b4dd6dec206905e3aaa7b0461d7c6d4cc3126a8"
|
||||
dependencies:
|
||||
"@pedroslopez/moduleraid": ^5.0.2
|
||||
archiver: ^5.3.1
|
||||
@@ -12758,7 +12949,7 @@ __metadata:
|
||||
optional: true
|
||||
unzipper:
|
||||
optional: true
|
||||
checksum: 637e53dffdaa80813a5cdd72e519f8f68978e00db17b39b471f39c8e2b98bc85643fe74168255a1dfdc655c71803e3d01b4ca6635bc6159c429dd59232ac07d4
|
||||
checksum: 441e54f450ed9ea5d5756c1ca4fd592e498ad79247d2c6508aee2a5c1b2608a9eb3f6360234f2f0ce563edb187a3d453d41773e745da9bebf657f575b9fa66b4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in new issue
Block a user