Compare commits

..
32 Commits
Author SHA1 Message Date
devlikepro 57672a2a9c [core] 2024.10.3
Release / amd64 - chrome - chrome (push) Waiting to run
Release / amd64 - chromium - latest (push) Waiting to run
Release / linux/arm64 - chromium - arm (push) Waiting to run
Release / amd64 - none - noweb (push) Waiting to run
Release / linux/arm64 - none - noweb-arm (push) Waiting to run
2024-10-03 14:50:52 +07:00
devlikepro 0ae594b198 [core] Add more logging in WEBJS 2024-10-03 14:50:27 +07:00
devlikepro 14a7e1c72d .env.example 2024-10-01 18:35:46 +07:00
devlikepro e570cbef12 [core] Up dashboard
Release / amd64 - chrome - chrome (push) Waiting to run
Release / amd64 - chromium - latest (push) Waiting to run
Release / linux/arm64 - chromium - arm (push) Waiting to run
Release / amd64 - none - noweb (push) Waiting to run
Release / linux/arm64 - none - noweb-arm (push) Waiting to run
2024-10-01 10:51:25 +07:00
devlikepro c6d732a723 [core] 2024.10.2 2024-10-01 10:50:36 +07:00
devlikepro 9cb0131a37 [core] Close store properly at the end 2024-10-01 10:50:19 +07:00
devlikepro d72b665cfe [core] update mongodb driver 2024-10-01 10:50:18 +07:00
devlikepro d6b87585f7 [core] log errors during periodic and one time jobs 2024-10-01 10:50:18 +07:00
devlikepro 2e01692e92 [core] comment mongo and minio 2024-09-29 18:20:22 +07:00
devlikepro 78ad79c08f [core] comment mongo and minio 2024-09-29 18:16:44 +07:00
devlikepro 725446a022 [core] fix .env 2024-09-29 17:48:23 +07:00
devlikepro 3bd7594b7f [core] no ssl 2024-09-29 17:41:14 +07:00
devlikepro 2bd314732a [core] Do not expose by default 2024-09-29 17:22:48 +07:00
devlikepro f4d7776bca [core] Adjust .env 2024-09-29 16:53:09 +07:00
devlikepro 80e13beb2b [core] Split .env 2024-09-29 16:51:22 +07:00
devlikepro 5c37826710 [core] protected 2024-09-29 16:35:24 +07:00
devlikepro 693a288839 [core] Move lock to SessionManager 2024-09-29 16:00:09 +07:00
devlikepro ecc0e1b60d [core] Allow to stop sessions even with no config 2024-09-29 15:43:52 +07:00
devlikepro 1d60a4ca42 [core] Update dashboard
Release / amd64 - chrome - chrome (push) Waiting to run
Release / amd64 - chromium - latest (push) Waiting to run
Release / linux/arm64 - chromium - arm (push) Waiting to run
Release / amd64 - none - noweb (push) Waiting to run
Release / linux/arm64 - none - noweb-arm (push) Waiting to run
2024-09-27 16:35:19 +07:00
devlikepro 7bf343d071 [core] 2024.10.1 2024-09-27 16:34:56 +07:00
devlikepro 0430b0ed53 [core] WEBJS - cancel check engine state job 2024-09-27 16:34:39 +07:00
devlikepro 9147dd9925 [core] jobs - do not log if it's not started 2024-09-27 16:34:39 +07:00
devlikepro b6e7fac619 [core] Up NOWEB 2024-09-27 16:34:38 +07:00
devlikepro c1d15e570d [core] Up WEBJS 2024-09-27 16:34:38 +07:00
devlikepro 72b067c8a7 [core] WEBJS restart session on WAState.OPENING
fix #552
2024-09-27 16:34:38 +07:00
devlikepro 94df9a681d [core] Add message.waiting event
fix #554
2024-09-27 16:34:38 +07:00
devlikepro 1d30bb7e8e [core] add WAHA_BASE_URL to override media URLs 2024-09-27 16:34:37 +07:00
devlikepro 0779e326d7 [core] add PORT for heroku support
fix #555
2024-09-27 16:34:37 +07:00
devlikepro 3ad5b67fef [core] Receive media in WAHA Core 2024-09-27 16:34:37 +07:00
devlikepro d747bf72fd [core] Use axios 2024-09-27 16:34:37 +07:00
devlikepro 8474cb5789 [core] Ignore pycache 2024-09-27 16:34:37 +07:00
devlikepro 83650c7dc9 [core] update dashboard 2024-09-19 17:48:38 +07:00
28 changed files with 911 additions and 715 deletions

No files matched your search

+165
View File
@@ -0,0 +1,165 @@
# WAHA Configuration
# https://waha.devlike.pro/docs/how-to/config/
#
# Common
#
# If you know the right URL, you can use it here.
# Use any port in WHATSAPP_API_PORT and domain in WHATSAPP_API_HOSTNAME
# https://waha.devlike.pro/docs/how-to/config/#common
#WHATSAPP_API_SCHEMA=http
#WHATSAPP_API_PORT=3000
#WHATSAPP_API_HOSTNAME=localhost
#WAHA_BASE_URL=http://localhost:3000
#
# Set your timezone to see the right time on screenshots
# Find your timezone name in the list
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#TZ=Europe/Dublin
#
# Security
#
# https://waha.devlike.pro/docs/how-to/security/
#
WHATSAPP_API_KEY=321
WAHA_DASHBOARD_USERNAME=waha
WAHA_DASHBOARD_PASSWORD=waha
#WHATSAPP_SWAGGER_USERNAME=admin
#WHATSAPP_SWAGGER_PASSWORD=admin
#
# Dashboard
#
# https://waha.devlike.pro/docs/how-to/waha-dashboard/#configuration
# Enabled by default
#WAHA_DASHBOARD_ENABLED=true
#WAHA_DASHBOARD_USERNAME=waha
#WAHA_DASHBOARD_PASSWORD=waha
#
# Logging
# https://waha.devlike.pro/docs/how-to/observability/#logging
#
# Set log format to JSON if you consume logs with log management systems
WAHA_LOG_FORMAT=JSON
WAHA_LOG_LEVEL=info
# WAHA_LOG_FORMAT=PRETTY
# If you want to see more logs, you can set the log level to debug
#WAHA_LOG_LEVEL=debug
# DEBUG=1 # shortcut for setting log level to debug
#
# Engine
# https://waha.devlike.pro/docs/how-to/engines/
#
# Choose the right engine for your needs (WEBJS by default)
WHATSAPP_DEFAULT_ENGINE=WEBJS
# Use NOWEB engine for the fastest performance
#WHATSAPP_DEFAULT_ENGINE=NOWEB
#
# Sessions
# https://waha.devlike.pro/docs/how-to/config/#sessions
#
# Restart all sessions when container starts
WHATSAPP_RESTART_ALL_SESSIONS=True
# Do not print QR codes in logs
WAHA_PRINT_QR=False
#
# OR you can specify sessions by name, if you have handful amount of sessions
#WHATSAPP_START_SESSION=session1,session2
# Do not use both WHATSAPP_RESTART_ALL_SESSIONS and WHATSAPP_START_SESSION parameters
#
#
# Swagger
# https://waha.devlike.pro/docs/how-to/swagger/
#
WHATSAPP_SWAGGER_USERNAME=admin
WHATSAPP_SWAGGER_PASSWORD=admin
# Disable Swagger
#WHATSAPP_SWAGGER_ENABLED=false
# Enable advanced Swagger configuration
#WHATSAPP_SWAGGER_CONFIG_ADVANCED=true
#
# Swagger White Label customization
# https://waha.devlike.pro/docs/how-to/swagger/#white-label
#WHATSAPP_SWAGGER_TITLE=WAHA API
#
#
# Global Proxy Settings
# https://waha.devlike.pro/docs/how-to/config/#global-proxy-configuration
#
# You can also set proxy settings for each session later when starting it
# https://waha.devlike.pro/docs/how-to/sessions/#configure-proxy
#WHATSAPP_PROXY_SERVER=proxy.example.com:3128
#WHATSAPP_PROXY_SERVER_USERNAME=user
#WHATSAPP_PROXY_SERVER_PASSWORD=pass
#
#
# HTTPS Configuration
# https://waha.devlike.pro/docs/how-to/config/#https
#
# Consider using certbot for HTTPS
# https://waha.devlike.pro/blog/setting-up-https-for-waha/#lets-encrypt-certbot--waha
#
#WAHA_HTTPS_ENABLED=true
#WAHA_HTTPS_PATH_KEY=/etc/letsencrypt/live/waha.example.pro/privkey.pem
#WAHA_HTTPS_PATH_CERT=/etc/letsencrypt/live/waha.example.pro/cert.pem \
#WAHA_HTTPS_PATH_CA=/etc/letsencrypt/live/waha.example.pro/chain.pem
#WHATSAPP_API_SCHEMA=https
#WHATSAPP_API_PORT=3000
#WHATSAPP_API_HOSTNAME=waha.example.pro
#
#
# Media Configuration
#
# https://waha.devlike.pro/docs/how-to/config/#files
#
# Disable media (images, videos, files) download for incoming messages
#WHATSAPP_DOWNLOAD_MEDIA=false
#
# Download only specific media types
#WHATSAPP_FILES_MIMETYPES=image/jpeg,image/png
#
# Media - Local Storage
# https://waha.devlike.pro/docs/how-to/storages/#media---local
#
# Set to 0 to keep media files forever
# https://waha.devlike.pro/docs/how-to/storages/#save-media-files-between-the-container-restarts
WAHA_MEDIA_STORAGE=LOCAL
WHATSAPP_FILES_LIFETIME=0
WHATSAPP_FILES_FOLDER=/app/.media
# Keep media files for 180 seconds (3 minutes)
#WHATSAPP_FILES_LIFETIME=180
#
# Media - S3 Storage
# https://waha.devlike.pro/docs/how-to/storages/#media---s3
#WAHA_MEDIA_STORAGE=S3
#WAHA_S3_REGION=eu-west-2
#WAHA_S3_BUCKET=waha
#WAHA_S3_ACCESS_KEY_ID=minioadmin
#WAHA_S3_SECRET_ACCESS_KEY=minioadmin
#WAHA_S3_ENDPOINT=http://minio:9000 # Not required if you're using AWS S3
#WAHA_S3_FORCE_PATH_STYLE=True # Required for Minio
#WAHA_S3_PROXY_FILES=True # Required for docker-compose setup
#
# Global Webhooks
#
# https://waha.devlike.pro/docs/how-to/config/#webhooks
# https://waha.devlike.pro/docs/how-to/webhooks/
#WHATSAPP_HOOK_URL=https://webhook.site/11111111-1111-1111-1111-11111111
#WHATSAPP_HOOK_EVENTS=session.status,message,message.reaction
#
#
# MongoDB Configuration
# https://waha.devlike.pro/docs/how-to/storages/#sessions---mongodb
#WHATSAPP_SESSIONS_MONGO_URL=mongodb://mongodb:27017
#
+2
View File
@@ -1,3 +1,4 @@
.env
*.heapsnapshot
.yarn
example.ts
@@ -15,6 +16,7 @@ test.js
.wwebjs_cache
src/dashboard
.eslintcache
__pycache__
# compiled output
/dist
+1 -1
View File
@@ -26,7 +26,7 @@ RUN yarn build && find ./dist -name "*.d.ts" -delete
FROM node:${NODE_VERSION} AS dashboard
# Download WAHA Dashboard
ENV WAHA_DASHBOARD_SHA 92dc0b84de69d8c126ecf6fc6bb469d8c7fa291f
ENV WAHA_DASHBOARD_SHA a3e3e31850af55161ca58cd8edb7dc9562707d14
RUN \
wget https://github.com/devlikeapro/dashboard/archive/${WAHA_DASHBOARD_SHA}.zip \
&& unzip ${WAHA_DASHBOARD_SHA}.zip -d /tmp/dashboard \
+1 -1
View File
@@ -35,7 +35,7 @@ up-noweb:
. ${NVM_DIR}/nvm.sh && nvm exec yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-2
up-webjs:
. ${NVM_DIR}/nvm.sh && nvm exec yarn up whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-webpack-exodus-channels
. ${NVM_DIR}/nvm.sh && nvm exec yarn up whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-channels
start-proxy:
docker run --rm -d --name squid-container -e TZ=UTC -p 3128:3128 ubuntu/squid:5.2-22.04_beta
+33 -223
View File
@@ -1,246 +1,56 @@
#
# https://waha.devlike.pro/docs/how-to/install/
# Here's we provide a simple example of how to install WAHA using Docker Compose.
#
# We're assuming you have Docker and Docker Compose installed.
# If you don't have Docker Compose installed, you can follow the official guide:
# https://docs.docker.com/compose/install/
#
services:
waha:
# Always restart the container on failure
restart: always
#
# Image
#
image: devlikeapro/waha-plus:latest # or devlikeapro/waha:latest if you're using WAHA Core
#
# We strongly recommend using the pinned version of WAHA
# https://waha.devlike.pro/docs/how-to/engines/#versions
# image: devlikeapro/waha-plus:latest-2024.7.6 # 'latest' is not mistaken here
#
# Multiple images are available
# https://waha.devlike.pro/docs/how-to/engines/#docker-images
# image: devlikeapro/waha-plus:chrome
#
# https://portal.devlike.pro/docker-image
image: devlikeapro/waha-plus:latest
# WAHA Core
# image: devlikeapro/waha:latest
# The first port can be any free port you want
# The second port must be the same as WHATSAPP_API_PORT or 3000 by default
# Consider using the same port for simplicity
ports:
- '3000:3000/tcp'
# NOTE: if you're using HTTP, you can use the following port mapping
#- '80:3000/tcp'
# NOTE: if you're using HTTPS, you can use the following port mapping
#- '443:3000/tcp'
- '127.0.0.1:3000:3000/tcp'
volumes:
# Store sessions in the .sessions folder (comment it if you're using MongoDB)
# Doesn't work with WAHA Core
- './.sessions:/app/.sessions'
# Save media files
# https://waha.devlike.pro/docs/how-to/storages/#save-media-files-between-the-container-restarts
- './.media:/app/.media'
# If you're using certbot for HTTPS, you can use the following volume mapping
# https://waha.devlike.pro/blog/setting-up-https-for-waha/#lets-encrypt-certbot--waha
# - '/etc/letsencrypt:/etc/letsencrypt'
# WAHA Configuration
# https://waha.devlike.pro/docs/how-to/config/
environment:
#
# Common
#
# If you know the right URL, you can use it here.
# Use any port in WHATSAPP_API_PORT and domain in WHATSAPP_API_HOSTNAME
# https://waha.devlike.pro/docs/how-to/config/#common
#- WHATSAPP_API_SCHEMA=http
#- WHATSAPP_API_PORT=3000
#- WHATSAPP_API_HOSTNAME=localhost
#
# Set your timezone to see the right time on screenshots
# Find your timezone name in the list
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#- TZ=Europe/Dublin
#
# Security
#
# https://waha.devlike.pro/docs/how-to/security/
#
- WHATSAPP_API_KEY=321
- WAHA_DASHBOARD_USERNAME=waha
- WAHA_DASHBOARD_PASSWORD=waha
#- WHATSAPP_SWAGGER_USERNAME=admin
#- WHATSAPP_SWAGGER_PASSWORD=admin
#
# Dashboard
#
# https://waha.devlike.pro/docs/how-to/waha-dashboard/#configuration
# Enabled by default
#- WAHA_DASHBOARD_ENABLED=true
#- WAHA_DASHBOARD_USERNAME=waha
#- WAHA_DASHBOARD_PASSWORD=waha
#
# Logging
# https://waha.devlike.pro/docs/how-to/observability/#logging
#
# Set log format to JSON if you consume logs with log management systems
- WAHA_LOG_FORMAT=JSON
- WAHA_LOG_LEVEL=info
# - WAHA_LOG_FORMAT=PRETTY
# If you want to see more logs, you can set the log level to debug
#- WAHA_LOG_LEVEL=debug
# DEBUG=1 # shortcut for setting log level to debug
#
# Engine
#
# Choose the right engine for your needs (WEBJS by default)
# https://waha.devlike.pro/docs/how-to/engines/
- WHATSAPP_DEFAULT_ENGINE=WEBJS
# Use NOWEB engine for the fastest performance
#- WHATSAPP_DEFAULT_ENGINE=NOWEB
#
# Sessions
#
# https://waha.devlike.pro/docs/how-to/config/#sessions
# Restart all sessions when container starts
- WHATSAPP_RESTART_ALL_SESSIONS=True
# Do not print QR codes in logs
- WAHA_PRINT_QR=False
#
# OR you can specify sessions by name, if you have handful amount of sessions
#- WHATSAPP_START_SESSION=session1,session2
# Do not use both WHATSAPP_RESTART_ALL_SESSIONS and WHATSAPP_START_SESSION parameters
#
#
# Swagger
#
# https://waha.devlike.pro/docs/how-to/swagger/
#- WHATSAPP_SWAGGER_USERNAME=admin
#- WHATSAPP_SWAGGER_PASSWORD=admin
# Disable Swagger
#- WHATSAPP_SWAGGER_ENABLED=false
# Enable advanced Swagger configuration
#- WHATSAPP_SWAGGER_CONFIG_ADVANCED=true
#
# Swagger White Label customization
# https://waha.devlike.pro/docs/how-to/swagger/#white-label
#- WHATSAPP_SWAGGER_TITLE=WAHA API
#
#
# Global Proxy Settings
# https://waha.devlike.pro/docs/how-to/config/#global-proxy-configuration
# You can also set proxy settings for each session later when starting it
# https://waha.devlike.pro/docs/how-to/sessions/#configure-proxy
#- WHATSAPP_PROXY_SERVER=proxy.example.com:3128
#-WHATSAPP_PROXY_SERVER_USERNAME=user
#-WHATSAPP_PROXY_SERVER_PASSWORD=pass
#
#
# HTTPS Configuration
#
# https://waha.devlike.pro/docs/how-to/config/#https
# Consider using certbot for HTTPS
# https://waha.devlike.pro/blog/setting-up-https-for-waha/#lets-encrypt-certbot--waha
#- WAHA_HTTPS_ENABLED=true
#- WAHA_HTTPS_PATH_KEY=/etc/letsencrypt/live/waha.example.pro/privkey.pem
#- WAHA_HTTPS_PATH_CERT=/etc/letsencrypt/live/waha.example.pro/cert.pem \
#- WAHA_HTTPS_PATH_CA=/etc/letsencrypt/live/waha.example.pro/chain.pem
#- WHATSAPP_API_SCHEMA=https
#- WHATSAPP_API_PORT=3000
#- WHATSAPP_API_HOSTNAME=waha.example.pro
#
#
# Media Configuration
#
# https://waha.devlike.pro/docs/how-to/config/#files
#
# Disable media (images, videos, files) download for incoming messages
#- WHATSAPP_DOWNLOAD_MEDIA=false
#
# Download only specific media types
#- WHATSAPP_FILES_MIMETYPES=image/jpeg,image/png
#
# Media - Local Storage
# https://waha.devlike.pro/docs/how-to/storages/#media---local
#
# Set to 0 to keep media files forever
# https://waha.devlike.pro/docs/how-to/storages/#save-media-files-between-the-container-restarts
- WAHA_MEDIA_STORAGE=LOCAL
- WHATSAPP_FILES_LIFETIME=0
- WHATSAPP_FILES_FOLDER=/app/.media
# Keep media files for 180 seconds (3 minutes)
#- WHATSAPP_FILES_LIFETIME=180
#
# Media - S3 Storage
# https://waha.devlike.pro/docs/how-to/storages/#media---s3
#- WAHA_MEDIA_STORAGE=S3
#- WAHA_S3_REGION=eu-west-2
#- WAHA_S3_BUCKET=waha
#- WAHA_S3_ACCESS_KEY_ID=minioadmin
#- WAHA_S3_SECRET_ACCESS_KEY=minioadmin
#- WAHA_S3_ENDPOINT=http://minio:9000 # Not required if you're using AWS S3
#- WAHA_S3_FORCE_PATH_STYLE=True # Required for Minio
#- WAHA_S3_PROXY_FILES=True # Required for docker-compose setup
#
# Global Webhooks
#
# https://waha.devlike.pro/docs/how-to/config/#webhooks
# https://waha.devlike.pro/docs/how-to/webhooks/
#- WHATSAPP_HOOK_URL=https://webhook.site/11111111-1111-1111-1111-11111111
#- WHATSAPP_HOOK_EVENTS=session.status,message,message.reaction
#
#
# MongoDB Configuration
# https://waha.devlike.pro/docs/how-to/storages/#sessions---mongodb
#- WHATSAPP_SESSIONS_MONGO_URL=mongodb://mongodb:27017
#
env_file:
- .env
# NOTE: Only if you're using MongoDB
# https://waha.devlike.pro/docs/how-to/storages/#sessions---mongodb
# Comment this block if you're using MongoDB
mongodb:
image: mongo
container_name: mongodb
ports:
- '27017:27017/tcp'
volumes:
- mongodb_data:/data/db
restart: always
# mongodb:
# image: mongo
# container_name: mongodb
# ports:
# - '127.0.0.1:27017:27017/tcp'
# volumes:
# - mongodb_data:/data/db
# restart: always
# NOTE: Only if you're using S3 to save media files
# https://waha.devlike.pro/docs/how-to/storages/#media---s3
# Comment this block if you're using AWS S3
minio:
image: quay.io/minio/minio
container_name: minio
restart: always
ports:
- '9000:9000'
- '9001:9001'
environment:
MINIO_REGION: 'eu-west-2'
MINIO_ROOT_USER: 'minioadmin'
MINIO_ROOT_PASSWORD: 'minioadmin'
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
# NOTE: Only if you're using S3 to save media files
# https://waha.devlike.pro/docs/how-to/storages/#media---s3
# Comment this block if you're using AWS S3
# minio:
# image: quay.io/minio/minio
# container_name: minio
# restart: always
# ports:
# - '127.0.0.1:9000:9000'
# - '127.0.0.1:9001:9001'
# environment:
# MINIO_REGION: 'eu-west-2'
# MINIO_ROOT_USER: 'minioadmin'
# MINIO_ROOT_PASSWORD: 'minioadmin'
# volumes:
# - minio_data:/data
# command: server /data --console-address ":9001"
volumes:
# NOTE: Only if you're using MongoDB
+5 -4
View File
@@ -42,7 +42,10 @@
"@types/lodash": "^4.14.194",
"@types/ws": "^8.5.4",
"adm-zip": "0.5.10",
"agentkeepalive": "^4.5.0",
"async-lock": "^1.4.1",
"axios": "^1.7.7",
"axios-retry": "^4.5.0",
"better-sqlite3": "11.3.0",
"check-disk-space": "^3.4.0",
"chokidar": "^3.6.0",
@@ -59,7 +62,7 @@
"link-preview-js": "^3.0.4",
"lodash": "^4.17.21",
"mime-types": "^2.1.27",
"mongodb": "^6.3.0",
"mongodb": "6.9.0",
"nestjs-pino": "^4.1.0",
"passport": "^0.6.0",
"passport-headerapikey": "^1.2.2",
@@ -71,13 +74,11 @@
"qrcode": "^1.5.1",
"qrcode-terminal": "^0.12.0",
"reflect-metadata": "^0.1.13",
"request": "^2.88.2",
"requestretry": "^4.1.1",
"rimraf": "^3.0.2",
"rxjs": "^7.1.0",
"sharp": "^0.33.4",
"swagger-ui-express": "^4.1.4",
"whatsapp-web.js": "github:devlikeapro/whatsapp-web.js#fork-webpack-exodus-channels"
"whatsapp-web.js": "github:devlikeapro/whatsapp-web.js#fork-main-channels"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
+2 -13
View File
@@ -35,21 +35,14 @@ import {
SessionUpdateRequest,
} from '../structures/sessions.dto';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const AsyncLock = require('async-lock');
@ApiSecurity('api_key')
@Controller('api/sessions')
@ApiTags('🖥️ Sessions')
class SessionsController {
private lock: any;
constructor(private manager: SessionManager) {
this.lock = new AsyncLock({ maxPending: Infinity });
}
constructor(private manager: SessionManager) {}
private withLock(name: string, fn: () => any) {
return this.lock.acquire(name, fn);
return this.manager.withLock(name, fn);
}
@Get('/')
@@ -177,10 +170,6 @@ class SessionsController {
@UsePipes(new WAHAValidationPipe())
async stop(@Param('session') name: string): Promise<SessionDTO> {
await this.withLock(name, async () => {
const exists = await this.manager.exists(name);
if (!exists) {
throw new NotFoundException('Session not found');
}
await this.manager.stop(name, false);
});
return await this.manager.getSessionInfo(name);
+13
View File
@@ -18,9 +18,22 @@ export class WhatsappConfigService {
}
get port(): string {
if (this.configService.get('PORT')) {
return this.configService.get('PORT');
}
return this.configService.get('WHATSAPP_API_PORT', '3000');
}
get baseUrl(): string {
let baseUrl = this.configService.get('WAHA_BASE_URL', '');
if (!baseUrl) {
// combine schema+hostname+port
baseUrl = `${this.schema}://${this.hostname}:${this.port}`;
}
// remove / at the end
return baseUrl.replace(/\/$/, '');
}
get mimetypes(): string[] {
if (!this.shouldDownloadMedia) {
return ['mimetype/ignore-all-media'];
+14 -1
View File
@@ -24,15 +24,28 @@ import { ISessionConfigRepository } from '../storage/ISessionConfigRepository';
import { WhatsappSession } from './session.abc';
import { WebhookConductor } from './webhooks.abc';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const AsyncLock = require('async-lock');
export abstract class SessionManager implements BeforeApplicationShutdown {
public store: any;
public sessionAuthRepository: ISessionAuthRepository;
public sessionConfigRepository: ISessionConfigRepository;
protected sessionMeRepository: ISessionMeRepository;
public events: EventEmitter;
private lock: any;
WAIT_STATUS_INTERVAL = 500;
WAIT_STATUS_TIMEOUT = 5_000;
protected constructor() {
this.lock = new AsyncLock({ maxPending: Infinity });
}
public withLock(name: string, fn: () => any) {
return this.lock.acquire(name, fn);
}
protected abstract getEngine(engine: WAHAEngine): typeof WhatsappSession;
protected abstract get EngineClass(): typeof WhatsappSession;
@@ -65,7 +78,7 @@ export abstract class SessionManager implements BeforeApplicationShutdown {
abstract getSessions(all: boolean): Promise<SessionInfo[]>;
handleSessionEvent(event: WAHAEvents, session: WhatsappSession) {
protected handleSessionEvent(event: WAHAEvents, session: WhatsappSession) {
return (payload: any) => {
const me = session.getSessionMeInfo();
const data: WAHAWebhook = {
+3 -1
View File
@@ -7,6 +7,7 @@ import { WhatsappSession } from './session.abc';
export abstract class WebhookSender {
protected url: string;
protected logger: Logger;
protected readonly config: WebhookConfig;
constructor(
loggerBuilder: LoggerBuilder,
@@ -14,9 +15,10 @@ export abstract class WebhookSender {
) {
this.url = webhookConfig.url;
this.logger = loggerBuilder.child({ name: WebhookSender.name });
this.config = webhookConfig;
}
abstract send(json);
abstract send(json: any): void;
}
export abstract class WebhookConductor {
+14 -1
View File
@@ -10,6 +10,7 @@ import {
ServerDebugController,
} from '@waha/api/server.controller';
import { WebsocketGatewayCore } from '@waha/core/api/websocket.gateway.core';
import { MediaLocalStorageModule } from '@waha/core/media/local/media.local.storage.module';
import { MediaLocalStorageConfig } from '@waha/core/media/local/MediaLocalStorageConfig';
import { BufferJsonReplacerInterceptor } from '@waha/nestjs/BufferJsonReplacerInterceptor';
import {
@@ -44,7 +45,7 @@ import { SwaggerConfigServiceCore } from './config/SwaggerConfigServiceCore';
import { WAHAHealthCheckServiceCore } from './health/WAHAHealthCheckServiceCore';
import { SessionManagerCore } from './manager.core';
export const IMPORTS = [
export const IMPORTS_CORE = [
LoggerModule.forRoot({
renameContext: 'name',
pinoHttp: {
@@ -100,6 +101,18 @@ export const IMPORTS = [
PassportModule,
TerminusModule,
];
const IMPORTS_MEDIA = [
ConfigModule.forRoot({
validationSchema: Joi.object({
WAHA_MEDIA_STORAGE: Joi.string().valid('LOCAL', 'S3').default('LOCAL'),
}),
}),
MediaLocalStorageModule,
];
const IMPORTS = [...IMPORTS_CORE, ...IMPORTS_MEDIA];
export const CONTROLLERS = [
AuthController,
SessionsController,
+54 -8
View File
@@ -19,6 +19,7 @@ import makeWASocket, {
WAMessageContent,
WAMessageKey,
} from '@adiwajshing/baileys';
import { downloadMediaMessage } from '@adiwajshing/baileys';
import { WACallEvent } from '@adiwajshing/baileys/lib/Types/Call';
import { Label as NOWEBLabel } from '@adiwajshing/baileys/lib/Types/Label';
import { LabelAssociationType } from '@adiwajshing/baileys/lib/Types/LabelAssociation';
@@ -49,6 +50,7 @@ import {
PollVotePayload,
WAMessageAckBody,
} from '@waha/structures/webhooks.dto';
import { LoggerBuilder } from '@waha/utils/logging';
import { waitUntil } from '@waha/utils/promiseTimeout';
import { SingleDelayedJobRunner } from '@waha/utils/SingleDelayedJobRunner';
import { SinglePeriodicJobRunner } from '@waha/utils/SinglePeriodicJobRunner';
@@ -275,6 +277,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
this.logger.error(`Failed to initialize storage or store: ${err}`);
this.status = WAHASessionStatus.FAILED;
this.end();
this.store?.close();
throw err;
});
} else {
@@ -405,6 +408,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
this.events.removeAllListeners();
this.startDelayedJob.cancel();
await this.end();
await this.store?.close();
return;
}
@@ -471,7 +475,6 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
// @ts-ignore
this.sock?.ev?.removeAllListeners();
this.sock?.ws?.removeAllListeners();
await this.store?.close();
// wait until connection is not connecting to avoid error:
// "WebSocket was closed before the connection was established"
await waitUntil(async () => !this.sock?.ws?.isConnecting, 1_000, 10_000);
@@ -1509,7 +1512,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
}
protected downloadMedia(message) {
const processor = new EngineMediaProcessor(this);
const processor = new NOWEBEngineMediaProcessor(this, this.loggerBuilder);
return this.mediaManager.processMedia(processor, message, this.name);
}
@@ -1526,23 +1529,66 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
}
}
export class EngineMediaProcessor implements IMediaEngineProcessor<any> {
constructor(public session: WhatsappSessionNoWebCore) {}
function hasPath(url: string) {
if (!url) {
return false;
}
try {
const urlObj = new URL(url);
return urlObj.pathname !== '/';
} catch (error) {
return false;
}
}
export class NOWEBEngineMediaProcessor implements IMediaEngineProcessor<any> {
private readonly logger: BaileysLogger;
constructor(
public session: WhatsappSessionNoWebCore,
loggerBuilder: LoggerBuilder,
) {
this.logger = loggerBuilder.child({
name: NOWEBEngineMediaProcessor.name,
}) as unknown as BaileysLogger;
}
hasMedia(message: any): boolean {
return Boolean(extractMediaContent(message.message));
}
getMessageId(message: any): string {
return '';
return message.key.id;
}
getMimetype(message: any): string {
return '';
const content = extractMediaContent(message.message);
return content.mimetype;
}
getMediaBuffer(message: any): Promise<Buffer | null> {
return Promise.resolve(undefined);
async getMediaBuffer(message: any): Promise<Buffer | null> {
const content = extractMediaContent(message.message);
// Fix Stickers
// https://github.com/devlikeapro/waha/issues/504
const url = content.url;
if (!hasPath(url)) {
// Set it to null so the engine handles it right
content.url = null;
}
return (await downloadMediaMessage(
message,
'buffer',
{},
{
logger: this.logger,
reuploadRequest: this.session.sock.updateMediaMessage,
},
).finally(() => {
// Fix Stickers - set url back, just to have it in the response
// https://github.com/devlikeapro/waha/issues/504
content.url = url;
})) as Buffer;
}
getFilename(message: any): string | null {
+73 -12
View File
@@ -69,7 +69,9 @@ import {
Label as WEBJSLabel,
Location,
Message,
MessageMedia,
Reaction,
WAState,
} from 'whatsapp-web.js';
import { Message as MessageInstance } from 'whatsapp-web.js/src/structures';
@@ -87,6 +89,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
protected engineConfig?: WebJSConfig;
private startDelayedJob: SingleDelayedJobRunner;
private engineStateCheckDelayedJob: SingleDelayedJobRunner;
private shouldRestart: boolean;
whatsapp: WebjsClient;
@@ -103,6 +106,11 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
this.START_ATTEMPT_DELAY_SECONDS * SECOND,
this.logger,
);
this.engineStateCheckDelayedJob = new SingleDelayedJobRunner(
'engine-state-check',
2 * SECOND,
this.logger,
);
}
/**
@@ -234,6 +242,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
}
private async end() {
this.engineStateCheckDelayedJob.cancel();
try {
this.whatsapp?.removeAllListeners();
this.whatsapp?.pupBrowser?.removeAllListeners();
@@ -296,22 +305,61 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
this.logger.info(`Session '${this.name}' is ready!`);
});
this.whatsapp.on(Events.AUTHENTICATED, () => {
this.whatsapp.on(Events.AUTHENTICATED, (args) => {
this.status = WAHASessionStatus.WORKING;
this.qr.save('');
this.logger.info(`Session '${this.name}' has been authenticated!`);
this.logger.info({ args: args }, `Session has been authenticated!`);
});
this.whatsapp.on(Events.AUTHENTICATION_FAILURE, () => {
this.whatsapp.on(Events.AUTHENTICATION_FAILURE, (args) => {
this.status = WAHASessionStatus.FAILED;
this.qr.save('');
this.logger.info(`Session '${this.name}' has been disconnected!`);
this.logger.info({ args: args }, `Session has failed to authenticate!`);
});
this.whatsapp.on(Events.DISCONNECTED, () => {
this.whatsapp.on(Events.DISCONNECTED, (args) => {
this.status = WAHASessionStatus.FAILED;
this.qr.save('');
this.logger.info(`Session '${this.name}' has been disconnected!`);
this.logger.info({ args: args }, `Session has been disconnected!`);
});
this.whatsapp.on(Events.STATE_CHANGED, (state: WAState) => {
const badStates = [WAState.OPENING, WAState.TIMEOUT];
const log = this.logger.child({ state: state, event: 'change_state' });
log.info('Session engine state changed');
if (!badStates.includes(state)) {
return;
}
log.info(`Session state changed to bad state, waiting for recovery...`);
this.engineStateCheckDelayedJob.schedule(async () => {
if (!this.startDelayedJob.scheduled) {
log.info('Session is restarting already, skip check.');
return;
}
if (!this.whatsapp) {
log.warn('Session is not initialized, skip recovery.');
return;
}
const currentState = await this.whatsapp.getState().catch((error) => {
log.error('Failed to get current state');
log.error(error, error.stack);
return null;
});
log.setBindings({ currentState: currentState });
if (!currentState) {
log.warn('Session has no current state, skip restarting.');
return;
} else if (badStates.includes(currentState)) {
log.info('Session is still in bad state, restarting...');
this.restartClient();
return;
}
log.info('Session has recovered, no need to restart.');
});
});
}
@@ -841,6 +889,11 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
this.processIncomingMessage(message).then(handler),
);
return true;
case WAHAEvents.MESSAGE_WAITING:
this.whatsapp.on(Events.MESSAGE_CIPHERTEXT, (message) =>
this.processIncomingMessage(message).then(handler),
);
return true;
case WAHAEvents.MESSAGE_REVOKED:
this.whatsapp.on(
Events.MESSAGE_REVOKED_EVERYONE,
@@ -991,7 +1044,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
}
protected downloadMedia(message: Message) {
const processor = new EngineMediaProcessor();
const processor = new WEBJSEngineMediaProcessor();
return this.mediaManager.processMedia(processor, message, this.name);
}
@@ -1008,7 +1061,9 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
}
}
export class EngineMediaProcessor implements IMediaEngineProcessor<Message> {
export class WEBJSEngineMediaProcessor
implements IMediaEngineProcessor<Message>
{
hasMedia(message: Message): boolean {
if (!message.hasMedia) {
return false;
@@ -1018,15 +1073,21 @@ export class EngineMediaProcessor implements IMediaEngineProcessor<Message> {
}
getMessageId(message: Message): string {
return '';
return message.id._serialized;
}
getMimetype(message: Message): string {
return '';
// @ts-ignore
return message.rawData.mimetype;
}
getMediaBuffer(message: Message): Promise<Buffer | null> {
return Promise.resolve(undefined);
async getMediaBuffer(message: Message): Promise<Buffer | null> {
return message.downloadMedia().then((media: MessageMedia) => {
if (!media) {
return null;
}
return Buffer.from(media.data, 'base64');
});
}
getFilename(message: Message): string | null {
+24 -7
View File
@@ -1,10 +1,9 @@
import {
Injectable,
LogLevel,
NotFoundException,
UnprocessableEntityException,
} from '@nestjs/common';
import { MediaNoopStorage } from '@waha/core/media/MediaNoopStorage';
import { MediaStorageFactory } from '@waha/core/media/MediaStorageFactory';
import { getPinoLogLevel, LoggerBuilder } from '@waha/utils/logging';
import { promiseTimeout, sleep } from '@waha/utils/promiseTimeout';
import { EventEmitter } from 'events';
@@ -31,7 +30,7 @@ import { WhatsappSessionNoWebCore } from './engines/noweb/session.noweb.core';
import { WhatsappSessionWebJSCore } from './engines/webjs/session.webjs.core';
import { DOCS_URL } from './exceptions';
import { getProxyConfig } from './helpers.proxy';
import { MediaManagerCore } from './media/MediaManagerCore';
import { MediaManager } from './media/MediaManager';
import { LocalSessionAuthRepository } from './storage/LocalSessionAuthRepository';
import { LocalStoreCore } from './storage/LocalStoreCore';
import { WebhookConductorCore } from './webhooks.core';
@@ -43,6 +42,7 @@ export class OnlyDefaultSessionIsAllowed extends UnprocessableEntityException {
);
}
}
enum DefaultSessionStatus {
REMOVED = undefined,
STOPPED = null,
@@ -67,6 +67,7 @@ export class SessionManagerCore extends SessionManager {
private config: WhatsappConfigService,
private engineConfigService: EngineConfigService,
private log: PinoLogger,
private mediaStorageFactory: MediaStorageFactory,
) {
super();
this.events = new EventEmitter();
@@ -78,6 +79,9 @@ export class SessionManagerCore extends SessionManager {
this.store = new LocalStoreCore(engineName.toLowerCase());
this.sessionAuthRepository = new LocalSessionAuthRepository(this.store);
this.startPredefinedSessions();
this.clearStorage().catch((error) => {
this.log.error({ error }, 'Error while clearing storage');
});
}
protected startPredefinedSessions() {
@@ -110,6 +114,13 @@ export class SessionManagerCore extends SessionManager {
await this.stop(this.DEFAULT, true);
}
private async clearStorage() {
const storage = this.mediaStorageFactory.build(
this.log.logger.child({ name: 'Storage' }),
);
await storage.purge();
}
//
// API Methods
//
@@ -136,14 +147,20 @@ export class SessionManagerCore extends SessionManager {
);
}
this.log.info(`'${name}' - starting session...`);
const mediaManager = new MediaManagerCore(
new MediaNoopStorage(),
this.config.mimetypes,
);
const logger = this.log.logger.child({ session: name });
logger.level = getPinoLogLevel(this.sessionConfig?.debug);
const loggerBuilder: LoggerBuilder = logger;
const storage = this.mediaStorageFactory.build(
loggerBuilder.child({ name: 'Storage' }),
);
await storage.init();
const mediaManager = new MediaManager(
storage,
this.config.mimetypes,
loggerBuilder.child({ name: 'MediaManager' }),
);
const webhook = new this.WebhookConductorClass(loggerBuilder);
const proxyConfig = this.getProxyConfig();
const sessionConfig: SessionParams = {
+198
View File
@@ -0,0 +1,198 @@
import { IMediaEngineProcessor } from '@waha/core/media/IMediaEngineProcessor';
import { IMediaManager } from '@waha/core/media/IMediaManager';
import {
IMediaStorage,
MediaData,
MediaStorageData,
} from '@waha/core/media/IMediaStorage';
import { WAMedia } from '@waha/structures/media.dto';
import { Logger } from 'pino';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const mime = require('mime-types');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const promiseRetry = require('promise-retry');
export class MediaManager implements IMediaManager {
// https://github.com/IndigoUnited/node-promise-retry
RETRY_OPTIONS = {
retries: 5,
minTimeout: 100,
maxTimeout: 500,
};
constructor(
private storage: IMediaStorage,
private mimetypes: string[],
protected log: Logger,
) {
// Log mimetypes
if (this.mimetypes && this.mimetypes.length > 0) {
const mimetypes = this.mimetypes.join(',');
const msg = `Only '${mimetypes}' mimetypes will be downloaded for the session`;
this.log.info(msg);
}
}
/**
* Check that we need to download files with the mimetype
*/
private shouldProcessMimetype(mimetype: string) {
// No specific mimetypes provided - always download
if (!this.mimetypes || this.mimetypes.length === 0) {
return true;
}
// Found "right" mimetype in the list of allowed mimetypes - download it
return this.mimetypes.some((type) => mimetype.startsWith(type));
}
private async processMediaInternal<Message>(
processor: IMediaEngineProcessor<Message>,
message: Message,
session: string,
): Promise<WAMedia | null> {
const messageId = processor.getMessageId(message);
const mimetype = processor.getMimetype(message);
const filename = processor.getFilename(message);
if (!this.shouldProcessMimetype(mimetype)) {
this.log.info(
`The message '${messageId}' has '${mimetype}' mimetype media, skip it.`,
);
return null;
}
const extension = mime.extension(mimetype);
const mediaData: MediaData = {
session: session,
message: {
id: messageId,
},
file: {
extension: extension,
filename: filename,
},
};
const exists = await this.withRetry('Checking media', () =>
this.exists(mediaData),
);
if (!exists) {
this.log.info(`The message ${messageId} has media, downloading it...`);
// Fetching media
const buffer = await this.withRetry('Fetching media', () =>
this.fetchMedia(message, processor),
);
// Saving media
await this.withRetry('Saving media', () =>
this.saveMedia(buffer, mediaData),
);
this.log.info(`The media from '${messageId}' has been saved.`);
}
const data = await this.withRetry('Getting media URL', () =>
this.getStorageData(mediaData),
);
return data;
}
async processMedia<Message>(
processor: IMediaEngineProcessor<Message>,
message: Message,
session: string,
): Promise<Message> {
let messageId: string;
try {
messageId = processor.getMessageId(message);
if (!processor.hasMedia(message)) {
return message;
}
} catch (error) {
this.log.error(
error,
`Error checking if message has media for message '${messageId}'`,
);
return message;
}
let media: WAMedia = {
url: null,
filename: null,
mimetype: null,
};
try {
media.filename = processor.getFilename(message);
media.mimetype = processor.getMimetype(message);
media.filename = processor.getFilename(message);
const data = await this.processMediaInternal(processor, message, session);
media = { ...media, ...data };
} catch (err) {
this.log.error(err, `Error processing media for message '${messageId}'`);
media.error = err;
// @ts-ignore
media.error.details = `${err.stack}`;
}
// @ts-ignore
message.media = media;
return message;
}
private async fetchMedia(
message: any,
processor: IMediaEngineProcessor<any>,
): Promise<Buffer> {
const messageId = processor.getMessageId(message);
this.log.debug(`Fetching media from WhatsApp message '${messageId}'...`);
const buffer = await processor.getMediaBuffer(message);
if (!buffer) {
throw new Error(
`Message '${messageId}' has no media, but it has media flag in the engine`,
);
}
return buffer;
}
private async saveMedia(
buffer: Buffer,
mediaData: MediaData,
): Promise<boolean> {
this.log.debug(
`Saving media from WhatsApp the message '${mediaData.message.id}'...`,
);
const result = await this.storage.save(buffer, mediaData);
this.log.debug(`The media from '${mediaData.message.id}' has been saved.`);
return result;
}
private async getStorageData(
mediaData: MediaData,
): Promise<MediaStorageData> {
return await this.storage.getStorageData(mediaData);
}
private async exists(mediaData: MediaData): Promise<boolean> {
this.log.trace(
`Checking if media exists for message '${mediaData.message.id}'...`,
);
const result = await this.storage.exists(mediaData);
this.log.trace(
`Media for message '${mediaData.message.id}' exists: ${result}`,
);
return result;
}
private async withRetry(name: string, fn: CallableFunction) {
const retryOptions = this.RETRY_OPTIONS;
try {
return await promiseRetry((retry: CallableFunction, number: number) => {
return fn().catch(retry);
}, retryOptions);
} catch (error) {
this.log.error(
error,
`Failed to execute '${name}', tried '${retryOptions.retries}' times`,
);
throw error;
}
}
}
-44
View File
@@ -1,44 +0,0 @@
import { IMediaEngineProcessor } from '@waha/core/media/IMediaEngineProcessor';
import { IMediaStorage, MediaData } from '@waha/core/media/IMediaStorage';
import { WAMedia } from '@waha/structures/media.dto';
import { IMediaManager } from './IMediaManager';
export class MediaManagerCore implements IMediaManager {
constructor(
private storage: IMediaStorage,
private mimetypes: string[],
) {}
async processMedia<Message>(
processor: IMediaEngineProcessor<Message>,
message: Message,
session: string,
): Promise<Message> {
if (!processor.hasMedia(message)) {
return message;
}
const mimetype = '';
const mediaData: MediaData = {
session: session,
message: {
id: '',
},
file: {
extension: '',
},
};
const { url } = await this.storage.getStorageData(mediaData);
const filename = processor.getFilename(message);
const media: WAMedia = {
mimetype: mimetype,
filename: filename,
url: url,
};
// @ts-ignore
message.media = media;
return message;
}
}
-25
View File
@@ -1,25 +0,0 @@
import { DOCS_URL } from '@waha/core/exceptions';
import { IMediaStorage, MediaData } from '@waha/core/media/IMediaStorage';
export class MediaNoopStorage implements IMediaStorage {
async init() {
return;
}
async save(buffer: Buffer, data: MediaData): Promise<boolean> {
return Promise.resolve(true);
}
async exists(data: MediaData): Promise<boolean> {
return false;
}
async getStorageData(data: MediaData) {
const url = `Media attachment's available only in WAHA Plus version. ${DOCS_URL}`;
return { url };
}
async purge() {
return;
}
}
+6
View File
@@ -0,0 +1,6 @@
import { IMediaStorage } from '@waha/core/media/IMediaStorage';
import { Logger } from 'pino';
export abstract class MediaStorageFactory {
abstract build(logger: Logger): IMediaStorage;
}
+95
View File
@@ -0,0 +1,95 @@
import { IMediaStorage, MediaData } from '@waha/core/media/IMediaStorage';
import { SECOND } from '@waha/structures/enums.dto';
import * as fsp from 'fs/promises';
import * as path from 'path';
import { Logger } from 'pino';
import { promisify } from 'util';
import fs = require('fs');
import del = require('del');
import { fileExists } from '@waha/utils/files';
const writeFileAsync = promisify(fs.writeFile);
/**
* Save files locally using the filesystem
*/
export class MediaLocalStorage implements IMediaStorage {
private readonly lifetimeMs: number;
constructor(
protected log: Logger,
private filesFolder: string,
private baseUrl: string,
lifetimeSeconds: number,
) {
this.lifetimeMs = lifetimeSeconds * SECOND;
if (this.lifetimeMs === 0) {
this.log.info('Files lifetime is 0, files will not be removed');
}
}
async init() {
return;
}
async exists(data: MediaData): Promise<boolean> {
const filepath = this.getFullPath(data);
return await fileExists(filepath);
}
public async save(buffer: Buffer, data: MediaData): Promise<boolean> {
const filepath = this.getFullPath(data);
const folder = path.dirname(filepath);
await fsp.mkdir(folder, { recursive: true });
await writeFileAsync(filepath, buffer);
this.postponeRemoval(filepath);
return true;
}
public async getStorageData(data: MediaData) {
const filename = this.getKey(data);
const url = this.baseUrl + filename;
return { url };
}
async purge() {
if (this.lifetimeMs === 0) {
this.log.info('No need to purge files with lifetime 0');
return;
}
if (fs.existsSync(this.filesFolder)) {
del([`${this.filesFolder}/*`], { force: true }).then((paths) => {
if (paths.length === 0) {
return;
}
this.log.info('Deleted files and directories:\n', paths.join('\n'));
});
} else {
fs.mkdirSync(this.filesFolder);
this.log.info(`Directory '${this.filesFolder}' created from scratch`);
}
}
private getKey(data: MediaData) {
return `${data.session}/${data.message.id}.${data.file.extension}`;
}
private getFullPath(data: MediaData) {
const filepath = this.getKey(data);
return path.resolve(`${this.filesFolder}/${filepath}`);
}
private postponeRemoval(filepath: string) {
if (this.lifetimeMs === 0) {
return;
}
setTimeout(
() =>
fs.unlink(filepath, () => {
this.log.info(`File ${filepath} was removed`);
}),
this.lifetimeMs,
);
}
}
@@ -8,7 +8,7 @@ export class MediaLocalStorageConfig {
constructor(private config: WhatsappConfigService) {}
get filesURL(): string {
return `${this.config.schema}://${this.config.hostname}:${this.config.port}${this.filesUri}/`;
return `${this.config.baseUrl}${this.filesUri}/`;
}
get filesFolder(): string {
@@ -0,0 +1,22 @@
import { Injectable } from '@nestjs/common';
import { IMediaStorage } from '@waha/core/media/IMediaStorage';
import { MediaLocalStorage } from '@waha/core/media/local/MediaLocalStorage';
import { MediaLocalStorageConfig } from '@waha/core/media/local/MediaLocalStorageConfig';
import { MediaStorageFactory } from '@waha/core/media/MediaStorageFactory';
import { Logger } from 'pino';
@Injectable()
export class MediaLocalStorageFactory extends MediaStorageFactory {
constructor(private config: MediaLocalStorageConfig) {
super();
}
build(logger: Logger): IMediaStorage {
return new MediaLocalStorage(
logger,
this.config.filesFolder,
this.config.filesURL,
this.config.filesLifetime,
);
}
}
@@ -0,0 +1,34 @@
import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { WhatsappConfigService } from '@waha/config.service';
import { MediaLocalStorageConfig } from '@waha/core/media/local/MediaLocalStorageConfig';
import { MediaLocalStorageFactory } from '@waha/core/media/local/MediaLocalStorageFactory';
import { MediaStorageFactory } from '@waha/core/media/MediaStorageFactory';
@Module({
imports: [
ServeStaticModule.forRootAsync({
imports: [],
extraProviders: [MediaLocalStorageConfig, WhatsappConfigService],
inject: [MediaLocalStorageConfig],
useFactory: (config: MediaLocalStorageConfig) => {
return [
{
rootPath: config.filesFolder,
serveRoot: config.filesUri,
},
];
},
}),
],
providers: [
{
provide: MediaStorageFactory,
useClass: MediaLocalStorageFactory,
},
WhatsappConfigService,
MediaLocalStorageConfig,
],
exports: [MediaStorageFactory],
})
export class MediaLocalStorageModule {}
+53 -14
View File
@@ -1,28 +1,67 @@
import { LoggerBuilder } from '@waha/utils/logging';
import Agent from 'agentkeepalive';
import axios from 'axios';
import { AxiosInstance } from 'axios';
import { Logger } from 'pino';
import { WAHAEvents } from '../structures/enums.dto';
import { WebhookConfig } from '../structures/webhooks.config.dto';
import { WAHAWebhook } from '../structures/webhooks.dto';
import { VERSION } from '../version';
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
import { WebhookConductor, WebhookSender } from './abc/webhooks.abc';
import request = require('request');
import { LoggerBuilder } from '@waha/utils/logging';
import { Logger } from 'pino';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const HttpAgent = require('agentkeepalive');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const HttpsAgent = require('agentkeepalive').HttpsAgent;
export class WebhookSenderCore extends WebhookSender {
send(json) {
protected static AGENTS = {
http: new HttpAgent({}),
https: new HttpsAgent({}),
};
protected axios: AxiosInstance;
constructor(loggerBuilder: LoggerBuilder, webhookConfig: WebhookConfig) {
super(loggerBuilder, webhookConfig);
this.axios = this.buildAxiosInstance();
}
protected buildAxiosInstance() {
const headers = {
'content-type': 'application/json',
'User-Agent': `WAHA/${VERSION.version}`,
};
return axios.create({
headers: headers,
httpAgent: WebhookSenderCore.AGENTS.http,
httpsAgent: WebhookSenderCore.AGENTS.https,
});
}
send(json: any, headers?: Record<string, string>) {
this.logger.info({ url: this.url }, `Sending POST ...`);
this.logger.debug({ data: json }, `POST DATA`);
request.post(this.url, { json: json }, (error, res, body) => {
if (error) {
this.logger.error(error);
return;
}
this.logger.info(
`POST request was sent with status code: ${res.statusCode}`,
);
this.logger.debug({ body: body }, `Response`);
});
this.axios
.post(this.url, json, { headers: headers })
.then((response) => {
this.logger.info(
`POST request was sent with status code: ${response.status}`,
);
this.logger.debug({ body: response.data }, `Response`);
})
.catch((error) => {
this.logger.error(
{
error: error.message,
data: error.response?.data,
},
`POST request failed: ${error.message}`,
);
});
}
}
+1
View File
@@ -6,6 +6,7 @@ export enum WAHAEvents {
MESSAGE_REACTION = 'message.reaction',
MESSAGE_ANY = 'message.any',
MESSAGE_ACK = 'message.ack',
MESSAGE_WAITING = 'message.waiting',
MESSAGE_REVOKED = 'message.revoked',
STATE_CHANGE = 'state.change',
GROUP_JOIN = 'group.join',
+17 -5
View File
@@ -22,8 +22,12 @@ export class SingleDelayedJobRunner {
});
}
get scheduled(): boolean {
return !!this.timeout;
}
schedule(fn: FunctionNoArgs): boolean {
if (this.timeout) {
if (this.scheduled) {
const msg = `Job has been started before, do not schedule it again`;
this.log(this.warningOverride, msg);
return false;
@@ -31,16 +35,24 @@ export class SingleDelayedJobRunner {
this.timeout = setTimeout(() => {
this.logger.debug(`Running job...`);
fn().finally(() => {
this.timeout = null;
this.logger.debug(`Job finished`);
});
fn()
.catch((error) => {
this.logger.error(`Job failed: ${error}`);
this.logger.error(error.stack);
})
.finally(() => {
this.timeout = null;
this.logger.debug(`Job finished`);
});
}, this.timeoutMs);
this.logger.info(`Job scheduled with timeout ${this.timeoutMs} ms`);
return true;
}
cancel() {
if (!this.timeout) {
return;
}
clearTimeout(this.timeout);
this.timeout = null;
this.logger.info(`Job cancelled`);
+12 -4
View File
@@ -40,16 +40,24 @@ export class SinglePeriodicJobRunner {
this.isWorking = true;
this.logger.debug('Running job...');
fn().finally(() => {
this.isWorking = false;
this.logger.debug(`Job finished`);
});
fn()
.catch((error) => {
this.logger.error(`Job failed: ${error}`);
this.logger.error(error.stack);
})
.finally(() => {
this.isWorking = false;
this.logger.debug(`Job finished`);
});
}, this.intervalMs);
this.logger.info(`Job started with interval ${this.intervalMs} ms`);
return true;
}
stop() {
if (!this.interval) {
return;
}
clearInterval(this.interval);
this.interval = null;
this.logger.info(`Job stopped`);
+1 -1
View File
@@ -33,7 +33,7 @@ export function getEngineName(): string {
}
export const VERSION: WAHAEnvironment = {
version: '2024.9.6',
version: '2024.10.3',
engine: getEngineName(),
tier: getWAHAVersion(),
browser: getBrowserExecutablePath(),
+67 -349
View File
@@ -7,7 +7,7 @@ __metadata:
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-2":
version: 6.7.7
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=84b7f66ea819a4abadddf41586192bb35916809c"
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=ffc61c22bea5143051ea6704fcf39d8d4bb52892"
dependencies:
"@adiwajshing/keyed-db": ^0.2.4
"@hapi/boom": ^9.1.3
@@ -39,7 +39,7 @@ __metadata:
optional: true
sharp:
optional: true
checksum: 670506c283521ff5d9a6e2baf08c1b0a99e1ad5b699a9ac088563bae39e623fae2ff7a679da6db3633f3bf91f8f8344f4433fd010535be0f196138500c632eda
checksum: 7254ddc761ab8235b645ad69ff998240df5636a4cdec97cefb26d7d43721839835d05663d57c95bd013318f9c7378a2a4882721c51a2cc055f9e1a92eaaa696c
languageName: node
linkType: hard
@@ -3752,13 +3752,6 @@ __metadata:
languageName: node
linkType: hard
"adm-zip@npm:^0.5.10":
version: 0.5.14
resolution: "adm-zip@npm:0.5.14"
checksum: 83a4bc0bdff70f3276992810db96b10ffbf3c07667a9c3395e3dc60ca40ecbb920812dde212e1e21633b1508f1ea6fc427ac451aa68ee1a597b7251b2c1fc844
languageName: node
linkType: hard
"agent-base@npm:6":
version: 6.0.2
resolution: "agent-base@npm:6.0.2"
@@ -3777,6 +3770,15 @@ __metadata:
languageName: node
linkType: hard
"agentkeepalive@npm:^4.5.0":
version: 4.5.0
resolution: "agentkeepalive@npm:4.5.0"
dependencies:
humanize-ms: ^1.2.1
checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481
languageName: node
linkType: hard
"aggregate-error@npm:^3.0.0":
version: 3.1.0
resolution: "aggregate-error@npm:3.1.0"
@@ -3822,7 +3824,7 @@ __metadata:
languageName: node
linkType: hard
"ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.3, ajv@npm:^6.12.5":
"ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.5":
version: 6.12.6
resolution: "ajv@npm:6.12.6"
dependencies:
@@ -4107,22 +4109,6 @@ __metadata:
languageName: node
linkType: hard
"asn1@npm:~0.2.3":
version: 0.2.6
resolution: "asn1@npm:0.2.6"
dependencies:
safer-buffer: ~2.1.0
checksum: 39f2ae343b03c15ad4f238ba561e626602a3de8d94ae536c46a4a93e69578826305366dc09fbb9b56aec39b4982a463682f259c38e59f6fa380cd72cd61e493d
languageName: node
linkType: hard
"assert-plus@npm:1.0.0, assert-plus@npm:^1.0.0":
version: 1.0.0
resolution: "assert-plus@npm:1.0.0"
checksum: 19b4340cb8f0e6a981c07225eacac0e9d52c2644c080198765d63398f0075f83bbc0c8e95474d54224e297555ad0d631c1dcd058adb1ddc2437b41a6b424ac64
languageName: node
linkType: hard
"ast-types@npm:^0.13.4":
version: 0.13.4
resolution: "ast-types@npm:0.13.4"
@@ -4213,17 +4199,14 @@ __metadata:
languageName: node
linkType: hard
"aws-sign2@npm:~0.7.0":
version: 0.7.0
resolution: "aws-sign2@npm:0.7.0"
checksum: b148b0bb0778098ad8cf7e5fc619768bcb51236707ca1d3e5b49e41b171166d8be9fdc2ea2ae43d7decf02989d0aaa3a9c4caa6f320af95d684de9b548a71525
languageName: node
linkType: hard
"aws4@npm:^1.8.0":
version: 1.13.0
resolution: "aws4@npm:1.13.0"
checksum: 71594a17a5f7b1a9151ef515500c18f1029caa51e2cb65c1b5b324d9bd8dac89896a9e296825d4e6befdcd612d7fc3b0d8042c667555a56df3ee1ab15d4d9b35
"axios-retry@npm:^4.5.0":
version: 4.5.0
resolution: "axios-retry@npm:4.5.0"
dependencies:
is-retry-allowed: ^2.2.0
peerDependencies:
axios: 0.x || 1.x
checksum: ec831e566ed3a55d3c3c927c1d42c52f2c2f1a8ea99ff8521d3675c6313f8c77f704c7186299fda08b7dc0f771a2c5471e72d279789d5aade65ec3755ab3a1ff
languageName: node
linkType: hard
@@ -4238,6 +4221,17 @@ __metadata:
languageName: node
linkType: hard
"axios@npm:^1.7.7":
version: 1.7.7
resolution: "axios@npm:1.7.7"
dependencies:
follow-redirects: ^1.15.6
form-data: ^4.0.0
proxy-from-env: ^1.1.0
checksum: 882d4fe0ec694a07c7f5c1f68205eb6dc5a62aecdb632cc7a4a3d0985188ce3030e0b277e1a8260ac3f194d314ae342117660a151fabffdc5081ca0b5a8b47fe
languageName: node
linkType: hard
"b4a@npm:^1.6.4":
version: 1.6.6
resolution: "b4a@npm:1.6.6"
@@ -4358,15 +4352,6 @@ __metadata:
languageName: node
linkType: hard
"bcrypt-pbkdf@npm:^1.0.0":
version: 1.0.2
resolution: "bcrypt-pbkdf@npm:1.0.2"
dependencies:
tweetnacl: ^0.14.3
checksum: 4edfc9fe7d07019609ccf797a2af28351736e9d012c8402a07120c4453a3b789a15f2ee1530dc49eee8f7eb9379331a8dd4b3766042b9e502f74a68e7f662291
languageName: node
linkType: hard
"better-sqlite3@npm:11.3.0":
version: 11.3.0
resolution: "better-sqlite3@npm:11.3.0"
@@ -4709,13 +4694,6 @@ __metadata:
languageName: node
linkType: hard
"caseless@npm:~0.12.0":
version: 0.12.0
resolution: "caseless@npm:0.12.0"
checksum: b43bd4c440aa1e8ee6baefee8063b4850fd0d7b378f6aabc796c9ec8cb26d27fb30b46885350777d9bd079c5256c0e1329ad0dc7c2817e0bb466810ebb353751
languageName: node
linkType: hard
"chainsaw@npm:~0.1.0":
version: 0.1.0
resolution: "chainsaw@npm:0.1.0"
@@ -5083,7 +5061,7 @@ __metadata:
languageName: node
linkType: hard
"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6":
"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8":
version: 1.0.8
resolution: "combined-stream@npm:1.0.8"
dependencies:
@@ -5202,13 +5180,6 @@ __metadata:
languageName: node
linkType: hard
"core-util-is@npm:1.0.2":
version: 1.0.2
resolution: "core-util-is@npm:1.0.2"
checksum: 7a4c925b497a2c91421e25bf76d6d8190f0b2359a9200dbeed136e63b2931d6294d3b1893eda378883ed363cd950f44a12a401384c609839ea616befb7927dab
languageName: node
linkType: hard
"core-util-is@npm:~1.0.0":
version: 1.0.3
resolution: "core-util-is@npm:1.0.3"
@@ -5355,15 +5326,6 @@ __metadata:
languageName: node
linkType: hard
"dashdash@npm:^1.12.0":
version: 1.14.1
resolution: "dashdash@npm:1.14.1"
dependencies:
assert-plus: ^1.0.0
checksum: 3634c249570f7f34e3d34f866c93f866c5b417f0dd616275decae08147dcdf8fccfaa5947380ccfb0473998ea3a8057c0b4cd90c875740ee685d0624b2983598
languageName: node
linkType: hard
"data-uri-to-buffer@npm:^6.0.2":
version: 6.0.2
resolution: "data-uri-to-buffer@npm:6.0.2"
@@ -5744,16 +5706,6 @@ __metadata:
languageName: node
linkType: hard
"ecc-jsbn@npm:~0.1.1":
version: 0.1.2
resolution: "ecc-jsbn@npm:0.1.2"
dependencies:
jsbn: ~0.1.0
safer-buffer: ^2.1.0
checksum: 22fef4b6203e5f31d425f5b711eb389e4c6c2723402e389af394f8411b76a488fa414d309d866e2b577ce3e8462d344205545c88a8143cc21752a5172818888a
languageName: node
linkType: hard
"ee-first@npm:1.1.1":
version: 1.1.1
resolution: "ee-first@npm:1.1.1"
@@ -6418,7 +6370,7 @@ __metadata:
languageName: node
linkType: hard
"extend@npm:^3.0.0, extend@npm:^3.0.2, extend@npm:~3.0.2":
"extend@npm:^3.0.0":
version: 3.0.2
resolution: "extend@npm:3.0.2"
checksum: a50a8309ca65ea5d426382ff09f33586527882cf532931cb08ca786ea3146c0553310bda688710ff61d7668eba9f96b923fe1420cdf56a2c3eaf30fcab87b515
@@ -6453,20 +6405,6 @@ __metadata:
languageName: node
linkType: hard
"extsprintf@npm:1.3.0":
version: 1.3.0
resolution: "extsprintf@npm:1.3.0"
checksum: cee7a4a1e34cffeeec18559109de92c27517e5641991ec6bab849aa64e3081022903dd53084f2080d0d2530803aa5ee84f1e9de642c365452f9e67be8f958ce2
languageName: node
linkType: hard
"extsprintf@npm:^1.2.0":
version: 1.4.1
resolution: "extsprintf@npm:1.4.1"
checksum: a2f29b241914a8d2bad64363de684821b6b1609d06ae68d5b539e4de6b28659715b5bea94a7265201603713b7027d35399d10b0548f09071c5513e65e8323d33
languageName: node
linkType: hard
"fast-copy@npm:^3.0.2":
version: 3.0.2
resolution: "fast-copy@npm:3.0.2"
@@ -6694,13 +6632,6 @@ __metadata:
languageName: node
linkType: hard
"forever-agent@npm:~0.6.1":
version: 0.6.1
resolution: "forever-agent@npm:0.6.1"
checksum: 766ae6e220f5fe23676bb4c6a99387cec5b7b62ceb99e10923376e27bfea72f3c3aeec2ba5f45f3f7ba65d6616965aa7c20b15002b6860833bb6e394dea546a8
languageName: node
linkType: hard
"fork-ts-checker-webpack-plugin@npm:8.0.0":
version: 8.0.0
resolution: "fork-ts-checker-webpack-plugin@npm:8.0.0"
@@ -6746,17 +6677,6 @@ __metadata:
languageName: node
linkType: hard
"form-data@npm:~2.3.2":
version: 2.3.3
resolution: "form-data@npm:2.3.3"
dependencies:
asynckit: ^0.4.0
combined-stream: ^1.0.6
mime-types: ^2.1.12
checksum: 10c1780fa13dbe1ff3100114c2ce1f9307f8be10b14bf16e103815356ff567b6be39d70fc4a40f8990b9660012dc24b0f5e1dde1b6426166eb23a445ba068ca3
languageName: node
linkType: hard
"formidable@npm:^1.2.0":
version: 1.2.6
resolution: "formidable@npm:1.2.6"
@@ -6997,15 +6917,6 @@ __metadata:
languageName: node
linkType: hard
"getpass@npm:^0.1.1":
version: 0.1.7
resolution: "getpass@npm:0.1.7"
dependencies:
assert-plus: ^1.0.0
checksum: ab18d55661db264e3eac6012c2d3daeafaab7a501c035ae0ccb193c3c23e9849c6e29b6ac762b9c2adae460266f925d55a3a2a3a3c8b94be2f222df94d70c046
languageName: node
linkType: hard
"github-from-package@npm:0.0.0":
version: 0.0.0
resolution: "github-from-package@npm:0.0.0"
@@ -7127,23 +7038,6 @@ __metadata:
languageName: node
linkType: hard
"har-schema@npm:^2.0.0":
version: 2.0.0
resolution: "har-schema@npm:2.0.0"
checksum: d8946348f333fb09e2bf24cc4c67eabb47c8e1d1aa1c14184c7ffec1140a49ec8aa78aa93677ae452d71d5fc0fdeec20f0c8c1237291fc2bcb3f502a5d204f9b
languageName: node
linkType: hard
"har-validator@npm:~5.1.3":
version: 5.1.5
resolution: "har-validator@npm:5.1.5"
dependencies:
ajv: ^6.12.3
har-schema: ^2.0.0
checksum: b998a7269ca560d7f219eedc53e2c664cd87d487e428ae854a6af4573fc94f182fe9d2e3b92ab968249baec7ebaf9ead69cf975c931dc2ab282ec182ee988280
languageName: node
linkType: hard
"has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2":
version: 1.0.2
resolution: "has-bigints@npm:1.0.2"
@@ -7262,17 +7156,6 @@ __metadata:
languageName: node
linkType: hard
"http-signature@npm:~1.2.0":
version: 1.2.0
resolution: "http-signature@npm:1.2.0"
dependencies:
assert-plus: ^1.0.0
jsprim: ^1.2.2
sshpk: ^1.7.0
checksum: 3324598712266a9683585bb84a75dec4fd550567d5e0dd4a0fff6ff3f74348793404d3eeac4918fa0902c810eeee1a86419e4a2e92a164132dfe6b26743fb47c
languageName: node
linkType: hard
"https-proxy-agent@npm:5.0.1":
version: 5.0.1
resolution: "https-proxy-agent@npm:5.0.1"
@@ -7307,6 +7190,15 @@ __metadata:
languageName: node
linkType: hard
"humanize-ms@npm:^1.2.1":
version: 1.2.1
resolution: "humanize-ms@npm:1.2.1"
dependencies:
ms: ^2.0.0
checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16
languageName: node
linkType: hard
"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24":
version: 0.4.24
resolution: "iconv-lite@npm:0.4.24"
@@ -7678,6 +7570,13 @@ __metadata:
languageName: node
linkType: hard
"is-retry-allowed@npm:^2.2.0":
version: 2.2.0
resolution: "is-retry-allowed@npm:2.2.0"
checksum: 3d1103a9290b5d03626756a41054844633eac78bc5d3e3a95b13afeae94fa3cfbcf7f0b5520d83f75f48a25ce7b142fdbac4217dc4b0630f3ea55e866ec3a029
languageName: node
linkType: hard
"is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.3":
version: 1.0.3
resolution: "is-shared-array-buffer@npm:1.0.3"
@@ -7721,13 +7620,6 @@ __metadata:
languageName: node
linkType: hard
"is-typedarray@npm:~1.0.0":
version: 1.0.0
resolution: "is-typedarray@npm:1.0.0"
checksum: 3508c6cd0a9ee2e0df2fa2e9baabcdc89e911c7bd5cf64604586697212feec525aa21050e48affb5ffc3df20f0f5d2e2cf79b08caa64e1ccc9578e251763aef7
languageName: node
linkType: hard
"is-unicode-supported@npm:^0.1.0":
version: 0.1.0
resolution: "is-unicode-supported@npm:0.1.0"
@@ -7772,13 +7664,6 @@ __metadata:
languageName: node
linkType: hard
"isstream@npm:~0.1.2":
version: 0.1.2
resolution: "isstream@npm:0.1.2"
checksum: 1eb2fe63a729f7bdd8a559ab552c69055f4f48eb5c2f03724430587c6f450783c8f1cd936c1c952d0a927925180fcc892ebd5b174236cf1065d4bd5bdb37e963
languageName: node
linkType: hard
"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0":
version: 3.2.2
resolution: "istanbul-lib-coverage@npm:3.2.2"
@@ -8390,13 +8275,6 @@ __metadata:
languageName: node
linkType: hard
"jsbn@npm:~0.1.0":
version: 0.1.1
resolution: "jsbn@npm:0.1.1"
checksum: e5ff29c1b8d965017ef3f9c219dacd6e40ad355c664e277d31246c90545a02e6047018c16c60a00f36d561b3647215c41894f5d869ada6908a2e0ce4200c88f2
languageName: node
linkType: hard
"jsesc@npm:^2.5.1":
version: 2.5.2
resolution: "jsesc@npm:2.5.2"
@@ -8427,13 +8305,6 @@ __metadata:
languageName: node
linkType: hard
"json-schema@npm:0.4.0":
version: 0.4.0
resolution: "json-schema@npm:0.4.0"
checksum: 66389434c3469e698da0df2e7ac5a3281bcff75e797a5c127db7c5b56270e01ae13d9afa3c03344f76e32e81678337a8c912bdbb75101c62e487dc3778461d72
languageName: node
linkType: hard
"json-stable-stringify-without-jsonify@npm:^1.0.1":
version: 1.0.1
resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
@@ -8441,13 +8312,6 @@ __metadata:
languageName: node
linkType: hard
"json-stringify-safe@npm:~5.0.1":
version: 5.0.1
resolution: "json-stringify-safe@npm:5.0.1"
checksum: 48ec0adad5280b8a96bb93f4563aa1667fd7a36334f79149abd42446d0989f2ddc58274b479f4819f1f00617957e6344c886c55d05a4e15ebb4ab931e4a6a8ee
languageName: node
linkType: hard
"json5@npm:^1.0.1, json5@npm:^1.0.2":
version: 1.0.2
resolution: "json5@npm:1.0.2"
@@ -8488,18 +8352,6 @@ __metadata:
languageName: node
linkType: hard
"jsprim@npm:^1.2.2":
version: 1.4.2
resolution: "jsprim@npm:1.4.2"
dependencies:
assert-plus: 1.0.0
extsprintf: 1.3.0
json-schema: 0.4.0
verror: 1.10.0
checksum: 2ad1b9fdcccae8b3d580fa6ced25de930eaa1ad154db21bbf8478a4d30bbbec7925b5f5ff29b933fba9412b16a17bd484a8da4fdb3663b5e27af95dd693bab2a
languageName: node
linkType: hard
"kleur@npm:^3.0.3":
version: 3.0.3
resolution: "kleur@npm:3.0.3"
@@ -8891,7 +8743,7 @@ __metadata:
languageName: node
linkType: hard
"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
version: 2.1.35
resolution: "mime-types@npm:2.1.35"
dependencies:
@@ -9110,9 +8962,9 @@ __metadata:
languageName: node
linkType: hard
"mongodb@npm:^6.3.0":
version: 6.7.0
resolution: "mongodb@npm:6.7.0"
"mongodb@npm:6.9.0":
version: 6.9.0
resolution: "mongodb@npm:6.9.0"
dependencies:
"@mongodb-js/saslprep": ^1.1.5
bson: ^6.7.0
@@ -9140,7 +8992,7 @@ __metadata:
optional: true
socks:
optional: true
checksum: 11677b416ba2bd8c8835663445b89db7f32faca763c5c3ce6d9de246826b4796ec628c35e84d1dc0b3c11be9623a1ebd6ecdb8eb90a40eededb8bc4fd75e4693
checksum: 754beb9acf605bbb4d55383fd1df1915ec25043f1e6ad0226d34a5d32b85ad822f784cf77d2751592696f5af72b5dc62a01514c4eb5fc0c7c0f495bf5764555a
languageName: node
linkType: hard
@@ -9167,7 +9019,7 @@ __metadata:
languageName: node
linkType: hard
"ms@npm:2.1.3, ms@npm:^2.1.1":
"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1":
version: 2.1.3
resolution: "ms@npm:2.1.3"
checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d
@@ -9402,13 +9254,6 @@ __metadata:
languageName: node
linkType: hard
"oauth-sign@npm:~0.9.0":
version: 0.9.0
resolution: "oauth-sign@npm:0.9.0"
checksum: 8f5497a127967866a3c67094c21efd295e46013a94e6e828573c62220e9af568cc1d2d04b16865ba583e430510fa168baf821ea78f355146d8ed7e350fc44c64
languageName: node
linkType: hard
"object-assign@npm:^4, object-assign@npm:^4.1.1":
version: 4.1.1
resolution: "object-assign@npm:4.1.1"
@@ -9823,13 +9668,6 @@ __metadata:
languageName: node
linkType: hard
"performance-now@npm:^2.1.0":
version: 2.1.0
resolution: "performance-now@npm:2.1.0"
checksum: 534e641aa8f7cba160f0afec0599b6cecefbb516a2e837b512be0adbe6c1da5550e89c78059c7fabc5c9ffdf6627edabe23eb7c518c4500067a898fa65c2b550
languageName: node
linkType: hard
"pg-connection-string@npm:2.6.2":
version: 2.6.2
resolution: "pg-connection-string@npm:2.6.2"
@@ -10221,13 +10059,6 @@ __metadata:
languageName: node
linkType: hard
"psl@npm:^1.1.28":
version: 1.9.0
resolution: "psl@npm:1.9.0"
checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d
languageName: node
linkType: hard
"pump@npm:^3.0.0":
version: 3.0.0
resolution: "pump@npm:3.0.0"
@@ -10245,7 +10076,7 @@ __metadata:
languageName: node
linkType: hard
"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0":
"punycode@npm:^2.1.0, punycode@npm:^2.3.0":
version: 2.3.1
resolution: "punycode@npm:2.3.1"
checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2
@@ -10366,13 +10197,6 @@ __metadata:
languageName: node
linkType: hard
"qs@npm:~6.5.2":
version: 6.5.3
resolution: "qs@npm:6.5.3"
checksum: 6f20bf08cabd90c458e50855559539a28d00b2f2e7dddcb66082b16a43188418cb3cb77cbd09268bcef6022935650f0534357b8af9eeb29bf0f27ccb17655692
languageName: node
linkType: hard
"querystring@npm:0.2.0":
version: 0.2.0
resolution: "querystring@npm:0.2.0"
@@ -10593,47 +10417,6 @@ __metadata:
languageName: node
linkType: hard
"request@npm:^2.88.2":
version: 2.88.2
resolution: "request@npm:2.88.2"
dependencies:
aws-sign2: ~0.7.0
aws4: ^1.8.0
caseless: ~0.12.0
combined-stream: ~1.0.6
extend: ~3.0.2
forever-agent: ~0.6.1
form-data: ~2.3.2
har-validator: ~5.1.3
http-signature: ~1.2.0
is-typedarray: ~1.0.0
isstream: ~0.1.2
json-stringify-safe: ~5.0.1
mime-types: ~2.1.19
oauth-sign: ~0.9.0
performance-now: ^2.1.0
qs: ~6.5.2
safe-buffer: ^5.1.2
tough-cookie: ~2.5.0
tunnel-agent: ^0.6.0
uuid: ^3.3.2
checksum: 4e112c087f6eabe7327869da2417e9d28fcd0910419edd2eb17b6acfc4bfa1dad61954525949c228705805882d8a98a86a0ea12d7f739c01ee92af7062996983
languageName: node
linkType: hard
"requestretry@npm:^4.1.1":
version: 4.1.2
resolution: "requestretry@npm:4.1.2"
dependencies:
extend: ^3.0.2
lodash: ^4.17.15
when: ^3.7.7
peerDependencies:
request: 2.*.*
checksum: 2dc43395c6d9b5b8dc5e1716db9014ea35185be46200ef067c56d28f356e799423a46e515f059f70402e2ada44fbaa41cad2d9103ca4be60f04ca465e8153d50
languageName: node
linkType: hard
"require-directory@npm:^2.1.1":
version: 2.1.1
resolution: "require-directory@npm:2.1.1"
@@ -10823,7 +10606,7 @@ __metadata:
languageName: node
linkType: hard
"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.2, safe-buffer@npm:~5.2.0":
"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0":
version: 5.2.1
resolution: "safe-buffer@npm:5.2.1"
checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491
@@ -10848,7 +10631,7 @@ __metadata:
languageName: node
linkType: hard
"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0, safer-buffer@npm:^2.0.2, safer-buffer@npm:^2.1.0, safer-buffer@npm:~2.1.0":
"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0":
version: 2.1.2
resolution: "safer-buffer@npm:2.1.2"
checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0
@@ -11273,27 +11056,6 @@ __metadata:
languageName: node
linkType: hard
"sshpk@npm:^1.7.0":
version: 1.18.0
resolution: "sshpk@npm:1.18.0"
dependencies:
asn1: ~0.2.3
assert-plus: ^1.0.0
bcrypt-pbkdf: ^1.0.0
dashdash: ^1.12.0
ecc-jsbn: ~0.1.1
getpass: ^0.1.1
jsbn: ~0.1.0
safer-buffer: ^2.0.2
tweetnacl: ~0.14.0
bin:
sshpk-conv: bin/sshpk-conv
sshpk-sign: bin/sshpk-sign
sshpk-verify: bin/sshpk-verify
checksum: 01d43374eee3a7e37b3b82fdbecd5518cbb2e47ccbed27d2ae30f9753f22bd6ffad31225cb8ef013bc3fb7785e686cea619203ee1439a228f965558c367c3cfa
languageName: node
linkType: hard
"ssri@npm:^10.0.0":
version: 10.0.6
resolution: "ssri@npm:10.0.6"
@@ -11854,16 +11616,6 @@ __metadata:
languageName: node
linkType: hard
"tough-cookie@npm:~2.5.0":
version: 2.5.0
resolution: "tough-cookie@npm:2.5.0"
dependencies:
psl: ^1.1.28
punycode: ^2.1.1
checksum: 16a8cd090224dd176eee23837cbe7573ca0fa297d7e468ab5e1c02d49a4e9a97bb05fef11320605eac516f91d54c57838a25864e8680e27b069a5231d8264977
languageName: node
linkType: hard
"tr46@npm:^4.1.1":
version: 4.1.1
resolution: "tr46@npm:4.1.1"
@@ -12060,13 +11812,6 @@ __metadata:
languageName: node
linkType: hard
"tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0":
version: 0.14.5
resolution: "tweetnacl@npm:0.14.5"
checksum: 6061daba1724f59473d99a7bb82e13f211cdf6e31315510ae9656fefd4779851cb927adad90f3b488c8ed77c106adc0421ea8055f6f976ff21b27c5c4e918487
languageName: node
linkType: hard
"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
version: 0.4.0
resolution: "type-check@npm:0.4.0"
@@ -12344,15 +12089,6 @@ __metadata:
languageName: node
linkType: hard
"uuid@npm:^3.3.2":
version: 3.4.0
resolution: "uuid@npm:3.4.0"
bin:
uuid: ./bin/uuid
checksum: 58de2feed61c59060b40f8203c0e4ed7fd6f99d42534a499f1741218a1dd0c129f4aa1de797bcf822c8ea5da7e4137aa3673431a96dae729047f7aca7b27866f
languageName: node
linkType: hard
"uuid@npm:^9.0.1":
version: 9.0.1
resolution: "uuid@npm:9.0.1"
@@ -12401,17 +12137,6 @@ __metadata:
languageName: node
linkType: hard
"verror@npm:1.10.0":
version: 1.10.0
resolution: "verror@npm:1.10.0"
dependencies:
assert-plus: ^1.0.0
core-util-is: 1.0.2
extsprintf: ^1.2.0
checksum: c431df0bedf2088b227a4e051e0ff4ca54df2c114096b0c01e1cbaadb021c30a04d7dd5b41ab277bcd51246ca135bf931d4c4c796ecae7a4fef6d744ecef36ea
languageName: node
linkType: hard
"waha@workspace:.":
version: 0.0.0-use.local
resolution: "waha@workspace:."
@@ -12444,7 +12169,10 @@ __metadata:
"@typescript-eslint/eslint-plugin": 3.9.1
"@typescript-eslint/parser": 3.9.1
adm-zip: 0.5.10
agentkeepalive: ^4.5.0
async-lock: ^1.4.1
axios: ^1.7.7
axios-retry: ^4.5.0
better-sqlite3: 11.3.0
check-disk-space: ^3.4.0
chokidar: ^3.6.0
@@ -12466,7 +12194,7 @@ __metadata:
link-preview-js: ^3.0.4
lodash: ^4.17.21
mime-types: ^2.1.27
mongodb: ^6.3.0
mongodb: 6.9.0
nestjs-pino: ^4.1.0
passport: ^0.6.0
passport-headerapikey: ^1.2.2
@@ -12479,8 +12207,6 @@ __metadata:
qrcode: ^1.5.1
qrcode-terminal: ^0.12.0
reflect-metadata: ^0.1.13
request: ^2.88.2
requestretry: ^4.1.1
rimraf: ^3.0.2
rxjs: ^7.1.0
sharp: ^0.33.4
@@ -12491,7 +12217,7 @@ __metadata:
ts-node: ^10.9.1
tsconfig-paths: ^4.1.0
typescript: ^4.8.4
whatsapp-web.js: "github:devlikeapro/whatsapp-web.js#fork-webpack-exodus-channels"
whatsapp-web.js: "github:devlikeapro/whatsapp-web.js#fork-main-channels"
languageName: unknown
linkType: soft
@@ -12588,12 +12314,11 @@ __metadata:
languageName: node
linkType: hard
"whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-webpack-exodus-channels":
version: 1.24.0
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=f28dad2d12136192e9ee45370d768323196c10c0"
"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=4c4cc9817bac3fc1369f09571f9efd2477ba10a9"
dependencies:
"@pedroslopez/moduleraid": ^5.0.2
adm-zip: ^0.5.10
archiver: ^5.3.1
fluent-ffmpeg: 2.1.2
fs-extra: ^10.1.0
@@ -12609,7 +12334,7 @@ __metadata:
optional: true
unzipper:
optional: true
checksum: 0bd28b1f332aafaa6f9d467de04c33da99c139208d03bef78c5323c0e3ada6762f31e156d63cc2f6a46bb90e298ad08ddd2db25e13fb045fc2d1a2e69595758b
checksum: ac30714d3e55fe9da1a1cd23db6988e1f060414a2b2c60e9d280938c4e620098da75edf85e54cd24efd976e884f5bc401e96d3cdabe583fae0332258f4d62b4d
languageName: node
linkType: hard
@@ -12633,13 +12358,6 @@ __metadata:
languageName: node
linkType: hard
"when@npm:^3.7.7":
version: 3.7.8
resolution: "when@npm:3.7.8"
checksum: 1f7a3d4a125c61108c51a58b7e42350d290f0595c42fb864a38d403101b40ede28d29068c9f7a8c3e4e0128f2050f7cc68c7e82b3a39a9156f6929fc69bf42fb
languageName: node
linkType: hard
"which-boxed-primitive@npm:^1.0.2":
version: 1.0.2
resolution: "which-boxed-primitive@npm:1.0.2"