Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
964d8dde9b | ||
|
|
bf794ce67f | ||
|
|
51dc9ea8c1 | ||
|
|
791a1fd475 | ||
|
|
244eb5f692 | ||
|
|
003bc33c25 | ||
|
|
b488b9f1df | ||
|
|
ff4f0a59af | ||
|
|
10e2c4bbd4 | ||
|
|
18536330ce | ||
|
|
e894069d4e | ||
|
|
5be2ca0deb | ||
|
|
83e2405151 | ||
|
|
220c0dfb01 | ||
|
|
5474f1ec0e | ||
|
|
dbd01abde8 | ||
|
|
83bbab0969 | ||
|
|
cc6808a6cd | ||
|
|
191fd89cfb | ||
|
|
42e5b46365 | ||
|
|
f444ce86f9 | ||
|
|
ce05b3d087 | ||
|
|
ab4dd28c51 | ||
|
|
9e23b287ff | ||
|
|
135c1ab10b | ||
|
|
de680c93f6 | ||
|
|
57ac57824f | ||
|
|
38df64c191 | ||
|
|
575969f938 | ||
|
|
42c388e5c9 |
No files matched your search
+6
-3
@@ -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
-1
@@ -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 \
|
||||
|
||||
@@ -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: {}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,7 +32,7 @@ import * as lodash from 'lodash';
|
||||
export class ServerController {
|
||||
private logger: Logger;
|
||||
|
||||
constructor() {
|
||||
constructor(private config: WhatsappConfigService) {
|
||||
this.logger = new Logger('ServerController');
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ export class ServerController {
|
||||
return {
|
||||
startTimestamp: startTimestamp,
|
||||
uptime: uptime,
|
||||
worker: {
|
||||
id: this.config.workerId,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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>' +
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import { LabelAssociationType } from '@adiwajshing/baileys/lib/Types/LabelAssoci
|
||||
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,
|
||||
@@ -209,7 +213,12 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
|
||||
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 {
|
||||
@@ -279,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();
|
||||
@@ -360,6 +363,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
);
|
||||
return;
|
||||
}
|
||||
await this.end();
|
||||
await this.start();
|
||||
});
|
||||
}
|
||||
@@ -393,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +415,7 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
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) => {
|
||||
@@ -423,9 +427,20 @@ export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
}
|
||||
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() {
|
||||
@@ -660,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: {
|
||||
@@ -669,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));
|
||||
@@ -1348,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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[];
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -159,6 +159,7 @@ export class MeInfo {
|
||||
|
||||
export class SessionInfo extends SessionDTO {
|
||||
me?: MeInfo;
|
||||
assignedWorker?: string;
|
||||
}
|
||||
|
||||
export class SessionDetailedInfo extends SessionInfo {
|
||||
|
||||
@@ -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
@@ -33,7 +33,7 @@ export function getEngineName(): string {
|
||||
}
|
||||
|
||||
export const VERSION: WAHAEnvironment = {
|
||||
version: '2024.10.4',
|
||||
version: '2024.10.5',
|
||||
engine: getEngineName(),
|
||||
tier: getWAHAVersion(),
|
||||
browser: getBrowserExecutablePath(),
|
||||
|
||||
@@ -12331,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
|
||||
@@ -12349,7 +12349,7 @@ __metadata:
|
||||
optional: true
|
||||
unzipper:
|
||||
optional: true
|
||||
checksum: ac30714d3e55fe9da1a1cd23db6988e1f060414a2b2c60e9d280938c4e620098da75edf85e54cd24efd976e884f5bc401e96d3cdabe583fae0332258f4d62b4d
|
||||
checksum: 51e9dce51270cf6fb20acd0bd7368f36763dcc3d28c6c3725c78b46edd5da21fea2c9c1f78ab6699464e4e1a6d9c361b6ab76a88225ebdeeb3f9abdd860d082c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in new issue
Block a user