Compare commits

..
45 Commits
Author SHA1 Message Date
devlikepro 964d8dde9b [core] await start
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-16 14:04:59 +07:00
devlikepro bf794ce67f [core] default 0 seconds delay 2024-10-16 14:03:32 +07:00
devlikepro 51dc9ea8c1 [core] Add restart back 2024-10-16 13:56:58 +07:00
devlikepro 791a1fd475 [core] 2024.10.5 2024-10-16 13:54:38 +07:00
devlikepro 244eb5f692 [core] Dashboard 2024-10-16 13:54:20 +07:00
devlikepro 003bc33c25 [core] Adjust logs 2024-10-16 13:53:16 +07:00
devlikepro b488b9f1df [core] Get body for buttons response 2024-10-16 13:53:15 +07:00
devlikepro ff4f0a59af [core] Provide button.id 2024-10-16 13:53:14 +07:00
devlikepro 10e2c4bbd4 [core] WEBJS - handle possible stuck STARTING
fix #586
2024-10-16 13:53:14 +07:00
devlikepro 18536330ce [core] Add WAHA_AUTO_START_DELAY_SECONDS
fix #586
2024-10-16 13:53:14 +07:00
devlikepro e894069d4e [core] fix NOWEB stuck in STARTING
fix #586
2024-10-16 13:53:13 +07:00
devlikepro 5be2ca0deb [core] delay policy
fix #587
2024-10-16 13:53:12 +07:00
devlikepro 83e2405151 [core] Button messages
fix #544
2024-10-16 13:53:12 +07:00
devlikepro 220c0dfb01 [core] Use waha logo 2024-10-16 13:53:10 +07:00
devlikepro 5474f1ec0e [core] Forward message
fix #158
2024-10-16 13:53:10 +07:00
devlikepro dbd01abde8 [core] Set FAILED before end 2024-10-16 13:53:10 +07:00
devlikepro 83bbab0969 [core] Add request id for webhooks in logs
fix #580
2024-10-16 13:53:09 +07:00
devlikepro cc6808a6cd [core] add asNote for /api/sendVideo
fix #585
2024-10-16 13:53:09 +07:00
devlikepro 191fd89cfb [core] Dashboard at the top 2024-10-16 13:53:09 +07:00
devlikepro 42e5b46365 [core] move docker-compose workers 2024-10-16 13:53:06 +07:00
devlikepro f444ce86f9 [core] no RESTART_ALL by default 2024-10-16 13:53:06 +07:00
devlikepro ce05b3d087 [core] Restore sessions 2024-10-16 13:53:06 +07:00
devlikepro ab4dd28c51 [core] docker-compose.workers.yaml 2024-10-16 13:53:05 +07:00
devlikepro 9e23b287ff [core] Use Sqlite3SchemaValidation for me repo 2024-10-16 13:53:05 +07:00
devlikepro 135c1ab10b [core] typo 2024-10-16 13:53:04 +07:00
devlikepro de680c93f6 [core] Do not check current session status 2024-10-16 13:53:04 +07:00
devlikepro 57ac57824f [core] Move startPredefinedSessions to SessionManager 2024-10-16 13:53:04 +07:00
devlikepro 38df64c191 [core] Move config to SessionManager 2024-10-16 13:53:04 +07:00
devlikepro 575969f938 [core] Move log to SessionManager 2024-10-16 13:53:04 +07:00
devlikepro 42c388e5c9 [core] Add waha logo in examples 2024-10-14 15:56:49 +07:00
devlikepro 6346433d45 [core] wait 10 seconds and stop
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-08 18:04:44 +07:00
devlikepro 44e63e00c3 [core] always 2024-10-08 17:55:36 +07:00
devlikepro 8648b44583 [core] stop all jobs before saving creds 2024-10-08 17:49:50 +07:00
devlikepro 086d540ee2 [core] 2024.10.4 2024-10-08 17:46:22 +07:00
devlikepro adf6836ee5 [core] no get app anymore 2024-10-08 17:46:03 +07:00
devlikepro 62f4406c51 [core] send SIGTERM 2024-10-08 17:46:03 +07:00
devlikepro e4c201e105 [core] exec node dist/main 2024-10-08 17:46:03 +07:00
devlikepro b6b0b1e7b3 [core] enable hooks before start listening 2024-10-08 17:46:03 +07:00
devlikepro 9d857d015f [core] Log signals 2024-10-08 17:46:03 +07:00
devlikepro 2055c595bb [core] NOWEB - save creds before stopping the session 2024-10-08 17:46:03 +07:00
devlikepro 00e33ceac7 [core] NOWEB - reuse store 2024-10-08 17:46:02 +07:00
devlikepro 77ef1ecebf [core] Update NOWEB
fix #567
2024-10-08 17:45:56 +07:00
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
36 changed files with 785 additions and 106 deletions

No files matched your search

+6 -3
View File
@@ -57,19 +57,22 @@ WHATSAPP_DEFAULT_ENGINE=WEBJS
# Use NOWEB engine for the fastest performance
#WHATSAPP_DEFAULT_ENGINE=NOWEB
# Worker
# WAHA_WORKER_ID=waha1
#
# 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
#
# Restart all sessions when container starts
# !!! Do not use it with multiple workers against one database !!!
# WHATSAPP_RESTART_ALL_SESSIONS=True
#
# Swagger
+1
View File
@@ -1,3 +1,4 @@
.env
*.heapsnapshot
.yarn
example.ts
+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 a3e3e31850af55161ca58cd8edb7dc9562707d14
ENV WAHA_DASHBOARD_SHA 5199c68522e81e911b440834fa7adc15ff4a1cf9
RUN \
wget https://github.com/devlikeapro/dashboard/archive/${WAHA_DASHBOARD_SHA}.zip \
&& unzip ${WAHA_DASHBOARD_SHA}.zip -d /tmp/dashboard \
+1 -1
View File
@@ -32,7 +32,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-2
. ${NVM_DIR}/nvm.sh && nvm exec yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-678
up-webjs:
. ${NVM_DIR}/nvm.sh && nvm exec yarn up whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-channels
@@ -0,0 +1,97 @@
# https://waha.devlike.pro/docs/how-to/install/
services:
# Just to connect
waha-dashboard:
restart: unless-stopped
image: devlikeapro/waha-plus:latest
ports:
- '127.0.0.1:3000:3000/tcp'
env_file:
- .env
environment:
- WAHA_WORKER_ID=waha-dashboard
waha1:
restart: unless-stopped
image: devlikeapro/waha-plus:latest
ports:
- '127.0.0.1:3001:3000/tcp'
volumes:
- './.media:/app/.media'
env_file:
- .env
environment:
- WAHA_WORKER_ID=waha1
- WAHA_BASE_URL=http://localhost:3001
- WHATSAPP_DEFAULT_ENGINE=NOWEB
# MongoDB
- WHATSAPP_SESSIONS_MONGO_URL=mongodb://mongodb:27017
# 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
waha2:
restart: unless-stopped
image: devlikeapro/waha-plus:latest
ports:
- '127.0.0.1:3002:3000/tcp'
volumes:
- './.media:/app/.media'
env_file:
- .env
environment:
- WAHA_WORKER_ID=waha2
- WAHA_BASE_URL=http://localhost:3002
- WHATSAPP_DEFAULT_ENGINE=NOWEB
# MongoDB
- WHATSAPP_SESSIONS_MONGO_URL=mongodb://mongodb:27017
# 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
# NOTE: Only if you're using MongoDB
# https://waha.devlike.pro/docs/how-to/storages/#sessions---mongodb
# Comment this block if you're not using MongoDB
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 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
mongodb_data: {}
minio_data: {}
-1
View File
@@ -14,7 +14,6 @@ services:
- WAHA_DASHBOARD_USERNAME=waha
- WAHA_DASHBOARD_PASSWORD=waha
- WHATSAPP_DEFAULT_ENGINE=WEBJS
- WHATSAPP_RESTART_ALL_SESSIONS=True
- WAHA_PRINT_QR=False
- WAHA_MEDIA_STORAGE=LOCAL
- WHATSAPP_FILES_LIFETIME=0
-2
View File
@@ -25,7 +25,6 @@ services:
- './.sessions:/app/.sessions'
environment:
# Environment variables from https://waha.devlike.pro/docs/how-to/config/
# - WHATSAPP_RESTART_ALL_SESSIONS=True
# - WHATSAPP_HOOK_URL=https://webhook.site/11111111-1111-1111-1111-11111111
# - WHATSAPP_HOOK_EVENTS=message
# - WHATSAPP_API_HOSTNAME=localhost
@@ -54,7 +53,6 @@ services:
- './.sessions:/app/.sessions'
environment:
# Environment variables from https://waha.devlike.pro/docs/how-to/config/
# - WHATSAPP_RESTART_ALL_SESSIONS=True
# - WHATSAPP_HOOK_URL=https://webhook.site/11111111-1111-1111-1111-11111111
# - WHATSAPP_HOOK_EVENTS=message
# - WHATSAPP_API_KEY=321
+1 -1
View File
@@ -8,4 +8,4 @@ uv_threadpool_size=$(($cpus * 2))
export UV_THREADPOOL_SIZE="${UV_THREADPOOL_SIZE:-$uv_threadpool_size}"
# Start your application using yarn
node dist/main
exec node dist/main
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+1 -1
View File
@@ -23,7 +23,7 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-2",
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-678",
"@adiwajshing/keyed-db": "^0.2.4",
"@aws-sdk/client-s3": "^3.633.0",
"@aws-sdk/s3-request-presigner": "^3.633.0",
-1
View File
@@ -14,7 +14,6 @@ docker run -d \
--env WAHA_LOG_FORMAT=JSON \
--env WAHA_LOG_LEVEL=info \
--env WHATSAPP_DEFAULT_ENGINE=WEBJS \
--env WHATSAPP_RESTART_ALL_SESSIONS=True \
--env WAHA_PRINT_QR=False \
--env WHATSAPP_FILES_LIFETIME=0 \
--env WHATSAPP_FILES_FOLDER=/app/.media \
+31 -1
View File
@@ -1,5 +1,15 @@
import { Body, Controller, Get, Post, Put, Query } from '@nestjs/common';
import {
Body,
Controller,
Get,
Post,
Put,
Query,
UsePipes,
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
import { SendButtonsRequest } from '@waha/structures/chatting.buttons.dto';
import { SessionManager } from '../core/abc/manager.abc';
import {
@@ -8,6 +18,7 @@ import {
GetMessageQuery,
MessageContactVcardRequest,
MessageFileRequest,
MessageForwardRequest,
MessageImageRequest,
MessageLinkPreviewRequest,
MessageLocationRequest,
@@ -81,6 +92,25 @@ export class ChattingController {
return whatsapp.sendVideo(request);
}
@Post('/sendButtons')
@ApiOperation({
summary: 'Send buttons (interactive message)',
description: 'Send Buttons',
})
@UsePipes(new WAHAValidationPipe())
async sendButtons(@Body() request: SendButtonsRequest) {
const whatsapp = await this.manager.getWorkingSession(request.session);
return whatsapp.sendButtons(request);
}
@Post('/forwardMessage')
async forwardMessage(
@Body() request: MessageForwardRequest,
): Promise<WAMessage> {
const whatsapp = await this.manager.getWorkingSession(request.session);
return await whatsapp.forwardMessage(request);
}
@Post('/sendSeen')
async sendSeen(@Body() chat: SendSeenRequest) {
const whatsapp = await this.manager.getWorkingSession(chat.session);
+8 -9
View File
@@ -9,14 +9,11 @@ import {
NotFoundException,
Post,
Query,
Res,
StreamableFile,
UseInterceptors,
UsePipes,
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { WhatsappConfigService } from '@waha/config.service';
import { getApp } from '@waha/main';
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
import { WAHAEnvironment } from '@waha/structures/environment.dto';
import {
@@ -25,6 +22,7 @@ import {
StopRequest,
StopResponse,
} from '@waha/structures/server.dto';
import { sleep } from '@waha/utils/promiseTimeout';
import { VERSION } from '@waha/version';
import * as lodash from 'lodash';
@@ -34,7 +32,7 @@ import * as lodash from 'lodash';
export class ServerController {
private logger: Logger;
constructor() {
constructor(private config: WhatsappConfigService) {
this.logger = new Logger('ServerController');
}
@@ -79,6 +77,9 @@ export class ServerController {
return {
startTimestamp: startTimestamp,
uptime: uptime,
worker: {
id: this.config.workerId,
},
};
}
@@ -97,16 +98,14 @@ export class ServerController {
setTimeout(() => {
this.logger.log('Force stopping the server');
process.kill(process.pid, 'SIGKILL');
process.exit(0);
}, timeout);
} else {
this.logger.log(`Gracefully stopping the server in ${timeout}ms`);
setTimeout(async () => {
this.logger.log('Gracefully closing the application...');
const app = getApp();
if (app) {
await app.close();
}
this.logger.log('Application closed');
process.kill(process.pid, 'SIGTERM');
await sleep(10_000);
process.exit(0);
}, timeout);
}
+11 -5
View File
@@ -91,6 +91,7 @@ class SessionsController {
const start = request.start || false;
await this.manager.upsert(name, config);
if (start) {
await this.manager.assign(name);
await this.manager.start(name);
}
});
@@ -133,6 +134,7 @@ class SessionsController {
@UsePipes(new WAHAValidationPipe())
async delete(@Param('session') name: string): Promise<void> {
await this.withLock(name, async () => {
await this.manager.unassign(name);
await this.manager.stop(name, true);
await this.manager.logout(name);
await this.manager.delete(name);
@@ -144,7 +146,7 @@ class SessionsController {
@ApiOperation({
summary: 'Start the session',
description:
'Start the session with the given name. The session must exist. Identity operation.',
'Start the session with the given name. The session must exist. Idempotent operation.',
})
@UsePipes(new WAHAValidationPipe())
async start(@Param('session') name: string): Promise<SessionDTO> {
@@ -153,10 +155,8 @@ class SessionsController {
if (!exists) {
throw new NotFoundException('Session not found');
}
const isRunning = this.manager.isRunning(name);
if (!isRunning) {
await this.manager.start(name);
}
await this.manager.assign(name);
await this.manager.start(name);
});
return await this.manager.getSessionInfo(name);
}
@@ -170,6 +170,7 @@ class SessionsController {
@UsePipes(new WAHAValidationPipe())
async stop(@Param('session') name: string): Promise<SessionDTO> {
await this.withLock(name, async () => {
await this.manager.unassign(name);
await this.manager.stop(name, false);
});
return await this.manager.getSessionInfo(name);
@@ -211,6 +212,7 @@ class SessionsController {
if (!exists) {
throw new NotFoundException('Session not found');
}
await this.manager.assign(name);
await this.manager.stop(name, true);
await this.manager.start(name);
});
@@ -237,6 +239,7 @@ class SessionsController {
return await this.withLock(name, async () => {
const config = request.config;
await this.manager.upsert(name, config);
await this.manager.assign(name);
return await this.manager.start(name);
});
}
@@ -254,12 +257,14 @@ class SessionsController {
if (request.logout) {
// Old API did remove the session complete
await this.withLock(name, async () => {
await this.manager.unassign(name);
await this.manager.stop(name, true);
await this.manager.logout(name);
await this.manager.delete(name);
});
} else {
await this.withLock(name, async () => {
await this.manager.unassign(name);
await this.manager.stop(name, false);
});
}
@@ -277,6 +282,7 @@ class SessionsController {
): Promise<void> {
const name = request.name;
await this.withLock(name, async () => {
await this.manager.unassign(name);
await this.manager.stop(name, true);
await this.manager.logout(name);
await this.manager.delete(name);
+21
View File
@@ -34,6 +34,27 @@ export class WhatsappConfigService {
return baseUrl.replace(/\/$/, '');
}
get workerId(): string {
return this.configService.get('WAHA_WORKER_ID', '');
}
get shouldRestartWorkerSessions(): boolean {
const value = this.configService.get(
'WAHA_WORKER_RESTART_SESSIONS',
'true',
);
return parseBool(value);
}
get autoStartDelaySeconds(): number {
const value = this.configService.get('WAHA_AUTO_START_DELAY_SECONDS', '0');
try {
return parseInt(value, 10);
} catch (error) {
return 0;
}
}
get mimetypes(): string[] {
if (!this.shouldDownloadMedia) {
return ['mimetype/ignore-all-media'];
+2 -2
View File
@@ -20,11 +20,11 @@ export class SwaggerConfiguratorCore {
get description() {
return (
'WhatsApp HTTP API that you can run in a click!<br/>' +
'<b>WhatsApp HTTP API</b> that you can run in a click!<br/>' +
'<a href="/dashboard"><b>📊 Dashboard</b></a><br/>' +
'<br/>' +
'Learn more:' +
'<ul>' +
'<li><a href="/dashboard">WAHA Dashboard</a></li>' +
'<li><a href="https://waha.devlike.pro/" target="_blank">Documentation</a></li>' +
'<li><a href="https://waha.devlike.pro/docs/how-to/engines/#features" target="_blank">Supported features in engines</a></li>' +
'<li><a href="https://github.com/devlikeapro/waha" target="_blank">GitHub - WAHA Core</a></li>' +
+35 -1
View File
@@ -2,11 +2,14 @@ import {
BeforeApplicationShutdown,
UnprocessableEntityException,
} from '@nestjs/common';
import { WhatsappConfigService } from '@waha/config.service';
import { ISessionMeRepository } from '@waha/core/storage/ISessionMeRepository';
import { ISessionWorkerRepository } from '@waha/core/storage/ISessionWorkerRepository';
import { WAHAWebhook } from '@waha/structures/webhooks.dto';
import { waitUntil } from '@waha/utils/promiseTimeout';
import { VERSION } from '@waha/version';
import { EventEmitter } from 'events';
import { PinoLogger } from 'nestjs-pino';
import {
WAHAEngine,
@@ -32,14 +35,33 @@ export abstract class SessionManager implements BeforeApplicationShutdown {
public sessionAuthRepository: ISessionAuthRepository;
public sessionConfigRepository: ISessionConfigRepository;
protected sessionMeRepository: ISessionMeRepository;
protected sessionWorkerRepository: ISessionWorkerRepository;
public events: EventEmitter;
private lock: any;
WAIT_STATUS_INTERVAL = 500;
WAIT_STATUS_TIMEOUT = 5_000;
protected constructor() {
protected constructor(
protected config: WhatsappConfigService,
protected log: PinoLogger,
) {
this.lock = new AsyncLock({ maxPending: Infinity });
this.log.setContext(SessionManager.name);
}
protected startPredefinedSessions() {
const startSessions = this.config.startSessions;
startSessions.forEach((sessionName) => {
this.withLock(sessionName, async () => {
const log = this.log.logger.child({ session: sessionName });
log.info(`Restarting PREDEFINED session...`);
await this.start(sessionName).catch((error) => {
log.error(`Failed to start PREDEFINED session: ${error}`);
log.error(error.stack);
});
});
});
}
public withLock(name: string, fn: () => any) {
@@ -78,6 +100,18 @@ export abstract class SessionManager implements BeforeApplicationShutdown {
abstract getSessions(all: boolean): Promise<SessionInfo[]>;
get workerId() {
return this.config.workerId;
}
async assign(name: string) {
await this.sessionWorkerRepository?.assign(name, this.workerId);
}
async unassign(name: string) {
await this.sessionWorkerRepository?.unassign(name, this.workerId);
}
protected handleSessionEvent(event: WAHAEvents, session: WhatsappSession) {
return (payload: any) => {
const me = session.getSessionMeInfo();
+9
View File
@@ -4,7 +4,9 @@ import {
ListChannelsQuery,
} from '@waha/structures/channels.dto';
import { GetChatsQuery } from '@waha/structures/chats.dto';
import { SendButtonsRequest } from '@waha/structures/chatting.buttons.dto';
import { Label, LabelID } from '@waha/structures/labels.dto';
import { WAMessage } from '@waha/structures/responses.dto';
import { LoggerBuilder } from '@waha/utils/logging';
import { EventEmitter } from 'events';
import * as fs from 'fs';
@@ -18,6 +20,7 @@ import {
GetMessageQuery,
MessageContactVcardRequest,
MessageFileRequest,
MessageForwardRequest,
MessageImageRequest,
MessageLinkPreviewRequest,
MessageLocationRequest,
@@ -279,6 +282,8 @@ export abstract class WhatsappSession {
throw new NotImplementedByEngineError();
}
abstract forwardMessage(request: MessageForwardRequest): Promise<WAMessage>;
abstract sendImage(request: MessageImageRequest);
abstract sendFile(request: MessageFileRequest);
@@ -289,6 +294,10 @@ export abstract class WhatsappSession {
throw new NotImplementedByEngineError();
}
sendButtons(request: SendButtonsRequest) {
throw new NotImplementedByEngineError();
}
abstract reply(request: MessageReplyRequest);
abstract sendSeen(chat: ChatRequest);
+107
View File
@@ -0,0 +1,107 @@
import { generateWAMessageFromContent, proto } from '@adiwajshing/baileys';
import { Button, ButtonType } from '@waha/structures/chatting.buttons.dto';
function toName(type: ButtonType) {
switch (type) {
case ButtonType.REPLY:
return 'quick_reply';
case ButtonType.URL:
return 'cta_url';
case ButtonType.CALL:
return 'cta_call';
case ButtonType.COPY:
return 'cta_copy';
}
}
export function randomId() {
// generate 16 random digits
return Math.random().toString().slice(2, 18);
}
export function buttonToJson(button: Button) {
const name = toName(button.type);
const buttonParams: any = {
display_text: button.text,
id: button.id || randomId(),
disabled: false,
};
switch (button.type) {
case ButtonType.REPLY:
break;
case ButtonType.CALL:
buttonParams.phone_number = button.phoneNumber;
break;
case ButtonType.COPY:
buttonParams.copy_code = button.copyCode;
break;
case ButtonType.URL:
buttonParams.url = button.url;
buttonParams.merchant_url = button.url;
break;
}
return {
name: name,
buttonParamsJson: JSON.stringify(buttonParams),
};
}
export async function sendButtonMessage(
sock: any,
chatId: string,
buttons: Button[],
header?: string,
headerImage?: any,
body?: string,
footer?: string,
) {
const data = {
viewOnceMessage: {
message: {
messageContextInfo: {
deviceListMetadata: {},
deviceListMetadataVersion: 2,
},
interactiveMessage: {
body: undefined,
header: undefined,
footer: undefined,
nativeFlowMessage: {
buttons: buttons.map(buttonToJson),
messageParamsJson: JSON.stringify({
from: 'api',
templateId: randomId(),
}),
},
},
},
},
};
if (header || headerImage) {
data.viewOnceMessage.message.interactiveMessage.header = {
title: header,
hasMediaAttachment: !!headerImage,
imageMessage: headerImage,
};
}
if (body) {
data.viewOnceMessage.message.interactiveMessage.body = {
text: body,
};
}
if (footer) {
data.viewOnceMessage.message.interactiveMessage.footer = {
text: footer,
};
}
const msg = proto.Message.fromObject(data);
const fullMessage = generateWAMessageFromContent(chatId, msg, {
userJid: sock?.user?.id,
});
await sock.relayMessage(chatId, fullMessage.message, {
messageId: fullMessage.key.id,
});
return fullMessage;
}
+92 -16
View File
@@ -2,6 +2,7 @@ import makeWASocket, {
Browsers,
Contact,
DisconnectReason,
downloadMediaMessage,
extractMessageContent,
getAggregateVotesInPollMessage,
getContentType,
@@ -19,13 +20,13 @@ 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';
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 { sendButtonMessage } from '@waha/core/engines/noweb/noweb.buttons';
import { NowebInMemoryStore } from '@waha/core/engines/noweb/store/NowebInMemoryStore';
import { IMediaEngineProcessor } from '@waha/core/media/IMediaEngineProcessor';
import { flipObject, parseBool, splitAt } from '@waha/helpers';
@@ -38,7 +39,9 @@ import {
ListChannelsQuery,
} from '@waha/structures/channels.dto';
import { GetChatsQuery } from '@waha/structures/chats.dto';
import { SendButtonsRequest } from '@waha/structures/chatting.buttons.dto';
import { ContactQuery, ContactRequest } from '@waha/structures/contacts.dto';
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
import {
Label,
LabelChatAssociation,
@@ -68,6 +71,7 @@ import {
MessageContactVcardRequest,
MessageDestination,
MessageFileRequest,
MessageForwardRequest,
MessageImageRequest,
MessageLinkPreviewRequest,
MessageLocationRequest,
@@ -163,6 +167,8 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
private msgRetryCounterCache: NodeCache;
protected engineLogger: BaileysLogger;
private authNOWEBStore: any;
get listenConnectionEventsFromTheStart() {
return true;
}
@@ -202,11 +208,17 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
delay * SECOND,
this.logger,
);
this.authNOWEBStore = null;
}
async start() {
this.status = WAHASessionStatus.STARTING;
await this.buildClient();
await this.buildClient().catch((err) => {
this.logger.error('Failed to start the client');
this.logger.error(err, err.stack);
this.status = WAHASessionStatus.FAILED;
this.restartClient();
});
}
getSocketConfig(agent, state): any {
@@ -240,10 +252,13 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
}
async makeSocket(): Promise<any> {
const { state, saveCreds } = await this.authFactory.buildAuth(
this.sessionStore,
this.name,
);
if (!this.authNOWEBStore) {
this.authNOWEBStore = await this.authFactory.buildAuth(
this.sessionStore,
this.name,
);
}
const { state, saveCreds } = this.authNOWEBStore;
const agent = this.makeAgent();
const socketConfig = this.getSocketConfig(agent, state);
const sock = makeWASocket(socketConfig);
@@ -273,13 +288,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
this.loggerBuilder.child({ name: NowebPersistentStore.name }),
storage,
);
await this.store.init().catch((err) => {
this.logger.error(`Failed to initialize storage or store: ${err}`);
this.status = WAHASessionStatus.FAILED;
this.end();
this.store?.close();
throw err;
});
await this.store.init();
} else {
this.logger.debug('Using NowebInMemoryStore');
this.store = new NowebInMemoryStore();
@@ -354,6 +363,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
);
return;
}
await this.end();
await this.start();
});
}
@@ -387,8 +397,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
this.logger.error(
`Connection closed due to '${lastDisconnect.error}', do not reconnect the session.`,
);
await this.end();
this.status = WAHASessionStatus.FAILED;
await this.failed();
}
}
@@ -404,12 +413,34 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
async stop() {
this.shouldRestart = false;
this.startDelayedJob.cancel();
this.autoRestartJob.stop();
if (this.authNOWEBStore && this.status == WAHASessionStatus.WORKING) {
this.logger.info('Saving creds before stopping...');
await this.authNOWEBStore.saveCreds().catch((e) => {
this.logger.error('Failed to save creds');
this.logger.error(e, e.stack);
});
this.logger.info('Creds saved');
this.authNOWEBStore = null;
}
this.status = WAHASessionStatus.STOPPED;
this.events.removeAllListeners();
await this.end();
await this.store?.close();
}
protected async failed() {
this.shouldRestart = false;
this.startDelayedJob.cancel();
this.autoRestartJob.stop();
this.status = WAHASessionStatus.FAILED;
await this.end();
await this.store?.close();
return;
}
private issueMessageUpdateOnEdits() {
@@ -644,6 +675,30 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
throw new AvailableInPlusVersion();
}
protected async uploadMedia(
file: RemoteFile | BinaryFile,
type,
): Promise<any> {
if (file && ('url' in file || 'data' in file)) {
throw new AvailableInPlusVersion('Sending media (image, video, pdf)');
}
return;
}
async sendButtons(request: SendButtonsRequest) {
const chatId = toJID(this.ensureSuffix(request.chatId));
const headerImage = await this.uploadMedia(request.headerImage, 'image');
return await sendButtonMessage(
this.sock,
chatId,
request.buttons,
request.header,
headerImage,
request.body,
request.footer,
);
}
sendLocation(request: MessageLocationRequest) {
return this.sock.sendMessage(request.chatId, {
location: {
@@ -653,6 +708,23 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
});
}
async forwardMessage(request: MessageForwardRequest): Promise<WAMessage> {
const key = parseMessageIdSerialized(request.messageId);
const forwardMessage = await this.store.loadMessage(key.remoteJid, key.id);
if (!forwardMessage) {
throw new UnprocessableEntityException(
`Message with id '${request.messageId}' not found`,
);
}
const chatId = toJID(this.ensureSuffix(request.chatId));
const message = {
forward: forwardMessage,
force: true,
};
const result = await this.sock.sendMessage(chatId, message, {});
return this.toWAMessage(result);
}
sendLinkPreview(request: MessageLinkPreviewRequest) {
const text = `${request.title}\n${request.url}`;
const chatId = toJID(this.ensureSuffix(request.chatId));
@@ -1332,6 +1404,10 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
// @ts-ignore - AudioMessage doesn't have caption field
body = mediaContent?.caption;
}
// Response for buttons
if (!body) {
body = message.templateButtonReplyMessage?.selectedDisplayText;
}
return body;
}
+24 -9
View File
@@ -26,6 +26,7 @@ import {
EditMessageRequest,
GetMessageQuery,
MessageFileRequest,
MessageForwardRequest,
MessageImageRequest,
MessageLocationRequest,
MessageReactionRequest,
@@ -229,7 +230,12 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
async start() {
this.status = WAHASessionStatus.STARTING;
await this.init();
await this.init().catch((err) => {
this.logger.error('Failed to start the client');
this.logger.error(err, err.stack);
this.status = WAHASessionStatus.FAILED;
this.restartClient();
});
return this;
}
@@ -305,29 +311,29 @@ 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.debug('Session engine state changed');
log.info('Session engine state changed');
if (!badStates.includes(state)) {
return;
}
@@ -384,7 +390,7 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
// show it as ABCD-ABCD
const parts = splitAt(code, 4);
const codeRepr = parts.join('-');
this.logger.info(`Your code: ${codeRepr}`);
this.logger.debug(`Your code: ${codeRepr}`);
return { code: codeRepr };
}
@@ -463,6 +469,15 @@ export class WhatsappSessionWebJSCore extends WhatsappSession {
return this.whatsapp.sendMessage(request.chatId, location, options);
}
async forwardMessage(request: MessageForwardRequest): Promise<WAMessage> {
const forwardMessage = this.recreateMessage(request.messageId);
const msg = await forwardMessage.forward(request.chatId);
// Return "sent: true" for now
// need to research how to get the data from WebJS
// @ts-ignore
return { sent: msg || false };
}
async sendSeen(request: SendSeenRequest) {
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
await chat.sendSeen();
+2 -2
View File
@@ -13,9 +13,9 @@ export class NotImplementedByEngineError extends UnprocessableEntityException {
}
export class AvailableInPlusVersion extends UnprocessableEntityException {
constructor() {
constructor(feature: string = 'The feature') {
super(
`The feature is available only in Plus version. Check this out: ${DOCS_URL}`,
`${feature} is available only in Plus version. Check this out: ${DOCS_URL}`,
);
}
}
+3 -11
View File
@@ -64,16 +64,15 @@ export class SessionManagerCore extends SessionManager {
protected readonly EngineClass: typeof WhatsappSession;
constructor(
private config: WhatsappConfigService,
config: WhatsappConfigService,
private engineConfigService: EngineConfigService,
private log: PinoLogger,
log: PinoLogger,
private mediaStorageFactory: MediaStorageFactory,
) {
super();
super(config, log);
this.events = new EventEmitter();
this.session = DefaultSessionStatus.STOPPED;
this.sessionConfig = null;
this.log.setContext(SessionManagerCore.name);
const engineName = this.engineConfigService.getDefaultEngineName();
this.EngineClass = this.getEngine(engineName);
this.store = new LocalStoreCore(engineName.toLowerCase());
@@ -84,13 +83,6 @@ export class SessionManagerCore extends SessionManager {
});
}
protected startPredefinedSessions() {
const startSessions = this.config.startSessions;
startSessions.forEach((sessionName) => {
this.start(sessionName);
});
}
protected getEngine(engine: WAHAEngine): typeof WhatsappSession {
if (engine === WAHAEngine.WEBJS) {
return WhatsappSessionWebJSCore;
@@ -0,0 +1,18 @@
export class SessionWorkerInfo {
id: string; // aka session name here
worker: string;
}
export abstract class ISessionWorkerRepository {
abstract assign(session: string, worker: string): Promise<void>;
abstract unassign(session: string, worker: string): Promise<void>;
abstract remove(session: string): Promise<void>;
abstract getAll(): Promise<SessionWorkerInfo[]>;
abstract getSessionsByWorker(worker: string): Promise<string[]>;
abstract init(): Promise<void>;
}
+2 -2
View File
@@ -1,8 +1,8 @@
import { NOWEBSqlite3KVRepository } from '@waha/core/engines/noweb/store/sqlite3/NOWEBSqlite3KVRepository';
import { Sqlite3SchemaValidation } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3SchemaValidation';
import { ISessionMeRepository } from '@waha/core/storage/ISessionMeRepository';
import { LocalStore } from '@waha/core/storage/LocalStore';
import { Field, Index, Schema } from '@waha/core/storage/sqlite3/Schema';
import { Sqlite3KVRepository } from '@waha/core/storage/sqlite3/Sqlite3KVRepository';
import { MeInfo } from '@waha/structures/sessions.dto';
import * as path from 'path';
@@ -21,7 +21,7 @@ class SessionMeInfo {
}
export class LocalSessionMeRepository
extends NOWEBSqlite3KVRepository<SessionMeInfo>
extends Sqlite3KVRepository<SessionMeInfo>
implements ISessionMeRepository
{
constructor(store: LocalStore) {
@@ -0,0 +1,74 @@
import { Sqlite3SchemaValidation } from '@waha/core/engines/noweb/store/sqlite3/Sqlite3SchemaValidation';
import {
ISessionWorkerRepository,
SessionWorkerInfo,
} from '@waha/core/storage/ISessionWorkerRepository';
import { LocalStore } from '@waha/core/storage/LocalStore';
import { Field, Index, Schema } from '@waha/core/storage/sqlite3/Schema';
import { Sqlite3KVRepository } from '@waha/core/storage/sqlite3/Sqlite3KVRepository';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Database = require('better-sqlite3');
const SCHEMA = new Schema(
'session_worker',
[
new Field('id', 'TEXT'),
new Field('worker', 'TEXT'),
new Field('data', 'TEXT'),
],
[
new Index('session_worker_id_idx', ['id']),
new Index('session_worker_worker_idx', ['worker']),
],
);
export class LocalSessionWorkerRepository
extends Sqlite3KVRepository<SessionWorkerInfo>
implements ISessionWorkerRepository
{
constructor(store: LocalStore) {
const db = store.getWAHADatabase();
super(db, SCHEMA);
}
assign(session: string, worker: string): Promise<void> {
return this.upsertOne({ id: session, worker: worker });
}
unassign(session: string, worker: string): Promise<void> {
return this.deleteBy({ id: session, worker: worker });
}
remove(session: string) {
return this.deleteById(session);
}
async getSessionsByWorker(worker: string): Promise<string[]> {
const data = await this.getAllBy({ worker: worker });
return data.map((d) => d.id);
}
async init(): Promise<void> {
this.migrations();
this.validateSchema();
}
private migrations() {
this.db.exec(
'CREATE TABLE IF NOT EXISTS session_worker (id TEXT, worker TEXT, data TEXT)',
);
// Session can have only one record
this.db.exec(
'CREATE UNIQUE INDEX IF NOT EXISTS session_worker_id_idx ON session_worker (id)',
);
// Worker can have multiple records
this.db.exec(
'CREATE INDEX IF NOT EXISTS session_worker_worker_idx ON session_worker (worker)',
);
}
private validateSchema() {
new Sqlite3SchemaValidation(SCHEMA, this.db).validate();
}
}
+15 -4
View File
@@ -42,20 +42,31 @@ export class WebhookSenderCore extends WebhookSender {
}
send(json: any, headers?: Record<string, string>) {
this.logger.info({ url: this.url }, `Sending POST ...`);
this.logger.debug({ data: json }, `POST DATA`);
this.logger.info(
{ id: headers['X-Webhook-Request-Id'], url: this.url },
`Sending POST...`,
);
this.logger.debug(
{ id: headers['X-Webhook-Request-Id'], data: json },
`POST DATA`,
);
this.axios
.post(this.url, json, { headers: headers })
.then((response) => {
this.logger.info(
{ id: headers['X-Webhook-Request-Id'] },
`POST request was sent with status code: ${response.status}`,
);
this.logger.debug({ body: response.data }, `Response`);
this.logger.debug(
{ id: headers['X-Webhook-Request-Id'], body: response.data },
`Response`,
);
})
.catch((error) => {
this.logger.error(
{
id: headers['X-Webhook-Request-Id'],
error: error.message,
data: error.response?.data,
},
@@ -160,7 +171,7 @@ export class WebhookConductorCore implements WebhookConductor {
if (!found) {
return false;
}
this.logger.info(`Event '${event}' is enabled for url: ${url}`);
this.logger.debug(`Event '${event}' is enabled for url: ${url}`);
return true;
}
+9 -8
View File
@@ -29,6 +29,13 @@ process.on('unhandledRejection', (reason, promise) => {
// @ts-ignore
logger.error(reason.stack);
});
process.on('SIGINT', () => {
logger.info('SIGINT received');
});
process.on('SIGTERM', () => {
logger.info('SIGTERM received');
});
async function loadModules(): Promise<
[typeof AppModuleCore, typeof SwaggerConfiguratorCore]
@@ -51,18 +58,12 @@ async function loadModules(): Promise<
return [AppModulePlus, SwaggerConfiguratorPlus];
}
let app = undefined;
export function getApp() {
return app;
}
async function bootstrap() {
const version = getWAHAVersion();
logger.info(`WAHA (WhatsApp HTTP API) - Running ${version} version...`);
const [AppModule, SwaggerModule] = await loadModules();
const httpsOptions = AppModule.getHttpsOptions(logger);
app = await NestFactory.create(AppModule, {
const app = await NestFactory.create(AppModule, {
logger: getNestJSLogLevels(),
httpsOptions: httpsOptions,
bufferLogs: true,
@@ -73,7 +74,6 @@ async function bootstrap() {
// https://github.com/iamolegga/nestjs-pino?tab=readme-ov-file#expose-stack-trace-and-error-class-in-err-property
app.useGlobalInterceptors(new LoggerErrorInterceptor());
app.enableShutdownHooks();
app.useGlobalFilters(new AllExceptionsFilter());
app.enableCors();
// Ideally, we should apply it globally.
@@ -90,6 +90,7 @@ async function bootstrap() {
swaggerConfigurator.configure(WAHA_WEBHOOKS);
AppModule.appReady(app, logger);
app.enableShutdownHooks();
const config = app.get(WhatsappConfigService);
await app.listen(config.port);
logger.info(`WhatsApp HTTP API is running on: ${await app.getUrl()}`);
+137
View File
@@ -0,0 +1,137 @@
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
import { WHATSAPP_DEFAULT_SESSION_NAME } from '@waha/structures/base.dto';
import { ChatRequest } from '@waha/structures/chatting.dto';
import { BinaryFile, RemoteFile } from '@waha/structures/files.dto';
import { ChatIdProperty } from '@waha/structures/properties.dto';
import { Type } from 'class-transformer';
import {
ArrayMaxSize,
ArrayMinSize,
IsArray,
IsEnum,
IsNotEmpty,
IsOptional,
IsString,
ValidateIf,
ValidateNested,
} from 'class-validator';
export enum ButtonType {
REPLY = 'reply',
URL = 'url',
CALL = 'call',
COPY = 'copy',
}
/**
* buttons:
* - type: reply|url|call|copy
* text: Display Text
* url: only for url (required)
* phone_number: only for call (required)
*/
export class Button {
@IsEnum(ButtonType)
type: ButtonType = ButtonType.REPLY;
@ApiProperty({
example: 'Button Text',
})
@IsString()
text: string;
@ApiProperty({
example: '321321',
})
@IsOptional()
@IsString()
id?: string;
@ApiProperty({
example: 'https://example.com',
})
@ValidateIf((o) => o.type === ButtonType.URL)
@IsNotEmpty()
url?: string;
@ApiProperty({
example: '+1234567890',
})
@ValidateIf((o) => o.type === ButtonType.CALL)
@IsNotEmpty()
phoneNumber?: string;
@ApiProperty({
example: '4321',
})
@ValidateIf((o) => o.type === ButtonType.COPY)
@IsNotEmpty()
copyCode?: string;
}
@ApiExtraModels(RemoteFile, BinaryFile)
export class SendButtonsRequest {
@IsString()
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
@ChatIdProperty()
@IsString()
chatId: string;
@ApiProperty({
example: 'How are you?',
})
@IsOptional()
header: string;
@ApiProperty({
oneOf: [
{ $ref: getSchemaPath(RemoteFile) },
{ $ref: getSchemaPath(BinaryFile) },
],
})
@IsOptional()
headerImage?: RemoteFile | BinaryFile;
@ApiProperty({
example: 'Tell us how are you please 🙏',
})
@IsOptional()
body: string;
@ApiProperty({
example: 'If you have any questions, please send it in the chat',
})
@IsOptional()
footer: string;
@ValidateNested({ each: true })
@Type(() => Button)
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(4)
@ApiProperty({
example: [
{
type: 'reply',
text: 'I am good!',
},
{
type: 'call',
text: 'Call us',
phoneNumber: '+1234567890',
},
{
type: 'copy',
text: 'Copy code',
copyCode: '4321',
},
{
type: 'url',
text: 'How did you do that?',
url: 'https://waha.devlike.pro',
},
],
})
buttons: Button[];
}
+13
View File
@@ -243,6 +243,12 @@ export class MessageVideoRequest extends ChatRequest {
example: null,
})
reply_to?: string;
@ApiProperty({
description: 'Send as video note (aka instant or round video).',
example: false,
})
asNote?: boolean;
}
export class MessageLinkPreviewRequest extends ChatRequest {
@@ -250,6 +256,13 @@ export class MessageLinkPreviewRequest extends ChatRequest {
title: string;
}
export class MessageForwardRequest extends ChatRequest {
@ApiProperty({
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
})
messageId: string;
}
export class MessageReactionRequest extends MessageRequest {
@ApiProperty({
description:
+2 -2
View File
@@ -21,7 +21,7 @@ export class RemoteFile {
@ApiProperty({
example:
process.env.WHATSAPP_SWAGGER_JPG_EXAMPLE_URL ||
'https://github.com/devlikeapro/waha/raw/core/examples/dev.likeapro.jpg',
'https://github.com/devlikeapro/waha/raw/core/examples/waha.jpg',
})
url: string;
}
@@ -42,7 +42,7 @@ export class BinaryFile {
@ApiProperty({
description: 'Base64-encoded data of the file',
example:
'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 Line truncated
})
data: string;
}
+10
View File
@@ -36,6 +36,14 @@ export class StopResponse {
stopping: boolean = true;
}
export class WorkerInfo {
@ApiProperty({
example: 'waha',
description: 'The worker ID.',
})
id: string;
}
export class ServerStatusResponse {
@ApiProperty({
example: 1723788847247,
@@ -48,4 +56,6 @@ export class ServerStatusResponse {
description: 'The uptime of the server in milliseconds.',
})
uptime: number;
worker: WorkerInfo;
}
+1
View File
@@ -159,6 +159,7 @@ export class MeInfo {
export class SessionInfo extends SessionDTO {
me?: MeInfo;
assignedWorker?: string;
}
export class SessionDetailedInfo extends SessionInfo {
+13
View File
@@ -11,6 +11,12 @@ import {
ValidateNested,
} from 'class-validator';
export enum RetryPolicy {
LINEAR = 'linear',
EXPONENTIAL = 'exponential',
CONSTANT = 'constant',
}
export class RetriesConfiguration {
@ApiProperty({
example: 2,
@@ -25,6 +31,13 @@ export class RetriesConfiguration {
@IsNumber()
@IsOptional()
attempts?: number;
@ApiProperty({
example: RetryPolicy.LINEAR,
})
@IsOptional()
@IsEnum(RetryPolicy)
policy?: RetryPolicy;
}
export class CustomHeader {
+1 -1
View File
@@ -33,7 +33,7 @@ export function getEngineName(): string {
}
export const VERSION: WAHAEnvironment = {
version: '2024.10.2',
version: '2024.10.5',
engine: getEngineName(),
tier: getWAHAVersion(),
browser: getBrowserExecutablePath(),
+37 -22
View File
@@ -5,16 +5,16 @@ __metadata:
version: 6
cacheKey: 8
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-2":
version: 6.7.7
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=ffc61c22bea5143051ea6704fcf39d8d4bb52892"
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-channels-678":
version: 6.7.8
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=d0323b92eb8365e6f32a61e41dd00010602d07f1"
dependencies:
"@adiwajshing/keyed-db": ^0.2.4
"@hapi/boom": ^9.1.3
async-lock: ^1.4.1
audio-decode: ^2.1.3
axios: ^1.6.0
cache-manager: 4.0.1
cache-manager: ^5.7.6
futoin-hkdf: ^1.5.1
libphonenumber-js: ^1.10.20
libsignal: "github:WhiskeySockets/libsignal-node"
@@ -39,7 +39,7 @@ __metadata:
optional: true
sharp:
optional: true
checksum: 7254ddc761ab8235b645ad69ff998240df5636a4cdec97cefb26d7d43721839835d05663d57c95bd013318f9c7378a2a4882721c51a2cc055f9e1a92eaaa696c
checksum: a3b461006443713074401a17c3481aef571301e83f1fba193d06e7f9ea4c47359b5c973d0b3804e34d4e48c35bdc1a64d8c3e59a0a744e5bc9bcca591d180901
languageName: node
linkType: hard
@@ -4132,13 +4132,6 @@ __metadata:
languageName: node
linkType: hard
"async@npm:3.2.3":
version: 3.2.3
resolution: "async@npm:3.2.3"
checksum: c4bee57ab2249af3dc83ca3ef9acfa8e822c0d5e5aa41bae3eaf7f673648343cd64ecd7d26091ffd357f3f044428b17b5f00098494b6cf8b6b3e9681f0636ca1
languageName: node
linkType: hard
"async@npm:>=0.2.9, async@npm:^3.2.4":
version: 3.2.5
resolution: "async@npm:3.2.5"
@@ -4642,14 +4635,15 @@ __metadata:
languageName: node
linkType: hard
"cache-manager@npm:4.0.1":
version: 4.0.1
resolution: "cache-manager@npm:4.0.1"
"cache-manager@npm:^5.7.6":
version: 5.7.6
resolution: "cache-manager@npm:5.7.6"
dependencies:
async: 3.2.3
eventemitter3: ^5.0.1
lodash.clonedeep: ^4.5.0
lru-cache: ^7.10.1
checksum: 8ca25b1e603111f033d1a3f1463b2a9203e9ea61a0706265a4d4f63d54a8be95f9e79efb04fc43103219becb4903a5db747a346e009e7102767a47e5677219b2
lru-cache: ^10.2.2
promise-coalesce: ^1.1.2
checksum: c61d30e2824f99f04af8e14a2e98c2274daa276cce82f64f0ac4c4bd59cf30e1ad9dec4028148206ad729196b242940476602e2f12496366d6f3f4b9da7c24c5
languageName: node
linkType: hard
@@ -6247,6 +6241,13 @@ __metadata:
languageName: node
linkType: hard
"eventemitter3@npm:^5.0.1":
version: 5.0.1
resolution: "eventemitter3@npm:5.0.1"
checksum: 543d6c858ab699303c3c32e0f0f47fc64d360bf73c3daf0ac0b5079710e340d6fe9f15487f94e66c629f5f82cd1a8678d692f3dbb6f6fcd1190e1b97fcad36f8
languageName: node
linkType: hard
"events@npm:^3.2.0, events@npm:^3.3.0":
version: 3.3.0
resolution: "events@npm:3.3.0"
@@ -8581,6 +8582,13 @@ __metadata:
languageName: node
linkType: hard
"lru-cache@npm:^10.2.2":
version: 10.4.3
resolution: "lru-cache@npm:10.4.3"
checksum: 6476138d2125387a6d20f100608c2583d415a4f64a0fecf30c9e2dda976614f09cad4baa0842447bd37dd459a7bd27f57d9d8f8ce558805abd487c583f3d774a
languageName: node
linkType: hard
"lru-cache@npm:^5.1.1":
version: 5.1.1
resolution: "lru-cache@npm:5.1.1"
@@ -8590,7 +8598,7 @@ __metadata:
languageName: node
linkType: hard
"lru-cache@npm:^7.10.1, lru-cache@npm:^7.14.1":
"lru-cache@npm:^7.14.1":
version: 7.18.3
resolution: "lru-cache@npm:7.18.3"
checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356
@@ -9955,6 +9963,13 @@ __metadata:
languageName: node
linkType: hard
"promise-coalesce@npm:^1.1.2":
version: 1.1.2
resolution: "promise-coalesce@npm:1.1.2"
checksum: 6f951b5db40ca78d09ad0f72adea0a2e9c5bdb0fc5b3ef218c611e2191c6ce2e9f752f815630fd07875dd1c9f04cc7327d6bada04b662dce986ce86ab88c2d5e
languageName: node
linkType: hard
"promise-retry@npm:^2.0.1":
version: 2.0.1
resolution: "promise-retry@npm:2.0.1"
@@ -12141,7 +12156,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "waha@workspace:."
dependencies:
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-2"
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-channels-678"
"@adiwajshing/keyed-db": ^0.2.4
"@aws-sdk/client-s3": ^3.633.0
"@aws-sdk/s3-request-presigner": ^3.633.0
@@ -12316,7 +12331,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=4c4cc9817bac3fc1369f09571f9efd2477ba10a9"
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=6a333d0088591269238726e9effa3cbb14c8e7c7"
dependencies:
"@pedroslopez/moduleraid": ^5.0.2
archiver: ^5.3.1
@@ -12334,7 +12349,7 @@ __metadata:
optional: true
unzipper:
optional: true
checksum: ac30714d3e55fe9da1a1cd23db6988e1f060414a2b2c60e9d280938c4e620098da75edf85e54cd24efd976e884f5bc401e96d3cdabe583fae0332258f4d62b4d
checksum: 51e9dce51270cf6fb20acd0bd7368f36763dcc3d28c6c3725c78b46edd5da21fea2c9c1f78ab6699464e4e1a6d9c361b6ab76a88225ebdeeb3f9abdd860d082c
languageName: node
linkType: hard