Compare commits

...
19 Commits
Author SHA1 Message Date
devlikepro 5784db8055 [core] 2025.11.3
Release / WEBJS - chrome - amd64 - chrome (push) Canceled after 0s
Release / WEBJS - chromium - amd64 - latest (push) Canceled after 0s
Release / WEBJS - chromium - linux/arm64 - arm (push) Canceled after 0s
Release / GOWS - none - amd64 - gows (push) Canceled after 0s
Release / GOWS - none - linux/arm64 - gows-arm (push) Canceled after 0s
Release / NOWEB - none - amd64 - noweb (push) Canceled after 0s
Release / NOWEB - none - linux/arm64 - noweb-arm (push) Canceled after 0s
2025-11-28 14:02:15 +07:00
devlikepro 6862063654 [core] Up GOWS 2025-11-28 14:02:14 +07:00
devlikepro 4aea282356 [core] ChatWoot - do not log binary 2025-11-28 14:02:13 +07:00
devlikepro 82ff15ae56 [core] GOWS - 10 mins deadline for media fetch 2025-11-28 14:02:12 +07:00
devlikepro 6cbf8cded2 [core] Up Dashboard - app id is uuid now 2025-11-28 14:02:11 +07:00
devlikepro 35e9418988 [core] add cpu profiling for troubleshooting 2025-11-28 14:02:10 +07:00
devlikepro a58be84e56 [core] GOWS - Use one grpc client to handle all sessions (but per session stream) 2025-11-28 14:02:09 +07:00
devlikepro 2994e0a54d [core] ignore tmp 2025-11-28 14:02:09 +07:00
devlikepro f16100e1d9 [core] GOWS - logs for grpc client closing 2025-11-28 14:02:07 +07:00
devlikepro e57be58d48 [core] GOWS - up grpc 2025-11-28 14:02:06 +07:00
devlikepro 7909910dc6 [core] ChatWoot - limit names to 255
fix #1556
2025-11-28 14:02:05 +07:00
devlikepro 7f1778ceb0 [core] ChatWoot - do not create new conversation when closed on message.ack
close devlikeapro/waha-plus#28
fix #1646
2025-11-28 14:02:05 +07:00
devlikepro aba90574d8 [core] ChatWoot - remove unused imports 2025-11-28 14:02:05 +07:00
devlikepro 33c945bf95 [core] NOWEB - Up engine 2025-11-28 14:02:04 +07:00
devlikepro d40e82eb02 [core] WEBJS - up engine 2025-11-28 14:02:04 +07:00
devlikepro 6e82d6f40b [core] GOWS - force to use cgo dns
fix #1649
2025-11-28 14:02:03 +07:00
devlikepro e193eb5696 [core] Up go 1.24
Tho we don't built anything here
2025-11-28 14:02:03 +07:00
devlikepro 8c63c4b097 [core] WEBJS - fix code pairing
fix #1651
2025-11-28 14:02:03 +07:00
devlikepro 4127d609cf [core] for-swagger 2025-11-28 14:02:03 +07:00
22 changed files with 348 additions and 78 deletions

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
tmp/*
Dockerfile
docker-compose
src/core/engines/gows/proto
+6
View File
@@ -32,6 +32,12 @@ WAHA_BASE_URL=http://localhost:3000
# WHATSAPP_API_HOSTNAME=localhost
# ===================
# ====== GOWS =======
# ===================
# By default, GOWS uses cgo (libc) DNS resolver
# You can ask to use golang one, but it's less reliable
# GODEBUG=netdns=go
# ===================
# ===== LOGGING =====
+1
View File
@@ -1,3 +1,4 @@
tmp/*
src/core/engines/gows/proto
.env
.envs/*
+4 -1
View File
@@ -1,5 +1,5 @@
ARG NODE_IMAGE_TAG=22.16-bookworm-slim
ARG GOLANG_IMAGE_TAG=1.23-bookworm
ARG GOLANG_IMAGE_TAG=1.24-bookworm
#
# Build
@@ -229,6 +229,9 @@ ENV CHOKIDAR_INTERVAL=5000
# WAHA variables
ENV WAHA_ZIPPER=ZIPUNZIP
# GOWS - use libc DNS resolver
ENV GODEBUG netdns=cgo
# Run command, etc
EXPOSE 3000
# Use tini as init system to handle zombie processes properly
+2 -2
View File
@@ -32,10 +32,10 @@ push:
docker push devlikeapro/waha
for-swagger:
WHATSAPP_SWAGGER_CONFIG_ADVANCED=true . ${NVM_DIR}/nvm.sh && nvm exec yarn start
WHATSAPP_SWAGGER_CONFIG_ADVANCED=true WHATSAPP_SWAGGER_PASSWORD=666 . ${NVM_DIR}/nvm.sh && nvm exec yarn start
up-noweb:
yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-11-07
yarn up @adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-11-21
up-noweb-libsignal:
yarn up libsignal@github:devlikeapro/libsignal-node#fork-master
+10
View File
@@ -70,6 +70,16 @@ else
fi
fi
#
# Enable CPU profiling
#
if [ "$WAHA_DEBUG_MODE" = "true" ] || [ "$WAHA_DEBUG_MODE" = "True" ] || [ "$WAHA_DEBUG_MODE" = "1" ]; then
case " $NODE_OPTIONS " in
*" --cpu-prof "*) ;;
*) export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--cpu-prof" ;;
esac
fi
#
# Start your application using node with exec to ensure proper signal handling
#
+4 -4
View File
@@ -26,7 +26,7 @@
"gows:proto": "yarn gows:proto:fetch && yarn gows:proto:build"
},
"dependencies": {
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-11-07",
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-11-21",
"@adiwajshing/keyed-db": "^0.2.4",
"@aws-sdk/client-s3": "^3.633.0",
"@aws-sdk/s3-request-presigner": "^3.633.0",
@@ -70,7 +70,7 @@
"express-basic-auth": "^1.2.1",
"file-type": "16.5.4",
"fs-extra": "^11.2.0",
"google-protobuf": "^3.21.4",
"google-protobuf": "^4.0.1",
"https-proxy-agent": "^7.0.0",
"ical.js": "^2.2.1",
"ioredis": "^5",
@@ -121,8 +121,8 @@
"axios": "^1.9.0"
},
"devDependencies": {
"@grpc/grpc-js": "^1.13.4",
"@grpc/proto-loader": "^0.7.13",
"@grpc/grpc-js": "^1.14.1",
"@grpc/proto-loader": "^0.8.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.0",
+56 -1
View File
@@ -1,4 +1,6 @@
import * as inspector from 'node:inspector';
import * as v8 from 'node:v8';
import { Readable } from 'node:stream';
import {
Controller,
@@ -18,7 +20,10 @@ import {
WorkingSessionParam,
} from '@waha/nestjs/params/SessionApiParam';
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
import { BrowserTraceQuery } from '@waha/structures/server.debug.dto';
import {
BrowserTraceQuery,
CpuProfileQuery,
} from '@waha/structures/server.debug.dto';
import { createReadStream } from 'fs';
@ApiSecurity('api_key')
@@ -36,6 +41,56 @@ export class ServerDebugController {
this.enabled = this.config.debugModeEnabled;
}
@Get('cpu')
@ApiOperation({
summary: 'Collect and return a CPU profile for the current nodejs process',
description: 'Uses the Node.js inspector profiler to capture a .cpuprofile',
})
@UsePipes(new WAHAValidationPipe())
async cpuProfile(@Query() query: CpuProfileQuery) {
if (!this.enabled) {
throw new NotFoundException('WAHA_DEBUG_MODE is disabled');
}
const { seconds } = query;
this.logger.log(`Collecting CPU profile for ${seconds}s...`);
const session = new inspector.Session();
session.connect();
const profile = await new Promise<inspector.Profiler.Profile>(
(resolve, reject) => {
session.post('Profiler.enable', (enableError) => {
if (enableError) {
session.disconnect();
return reject(enableError);
}
session.post('Profiler.start', (startError) => {
if (startError) {
session.disconnect();
return reject(startError);
}
setTimeout(() => {
session.post('Profiler.stop', (stopError, params) => {
session.disconnect();
if (stopError) {
return reject(stopError);
}
resolve(params.profile);
});
}, seconds * 1000);
});
});
},
);
const filename = `CPU.${Date.now()}.${process.pid}.cpuprofile`;
const stream = Readable.from([JSON.stringify(profile)]);
return new StreamableFile(stream, {
type: 'application/json',
disposition: `attachment; filename=${filename}`,
});
}
@Get('heapsnapshot')
@ApiOperation({
summary: 'Return a heapsnapshot for the current nodejs process',
+14 -5
View File
@@ -29,13 +29,22 @@ export class AxiosLogging {
const { method, url } = response.config;
const status = response.status;
const methodStr = method?.toUpperCase() ?? 'GET';
const responseData = JSON.stringify(response.data);
if (status >= 200 && status < 400) {
this.logger.debug(`${methodStr} ${status}:OK ${url}`);
this.logger.trace(`${methodStr} ${status}:OK ${url} ${responseData}`);
const type: any = response.headers['content-type'];
// Log warnings for non-2xx/3xx responses
if (status < 200 || status >= 400) {
const data = JSON.stringify(response.data);
this.logger.warn(`${methodStr} ${status} ${url} ${data}`);
return response;
}
// Log debug for 2xx/3xx responses
this.logger.debug(`${methodStr} ${status}:OK ${url}`);
if (type.startsWith('application/json')) {
const data = JSON.stringify(response.data);
this.logger.trace(`${methodStr} ${status}:OK ${url} ${data}`);
} else {
this.logger.warn(`${methodStr} ${status} ${url} ${responseData}`);
this.logger.trace(`${methodStr} ${status}:OK ${url} [${type}]`);
}
return response;
@@ -10,6 +10,7 @@ import {
import { Conversation } from '@waha/apps/chatwoot/client/Conversation';
import {
ContactIds,
ConversationResult,
ConversationService,
} from '@waha/apps/chatwoot/client/ConversationService';
import { ChatWootAPIConfig } from '@waha/apps/chatwoot/client/interfaces';
@@ -43,9 +44,10 @@ export class ContactConversationService {
this.cache = CacheForConfig(config);
}
public async upsertByContactInfo(
private async getByContactInfo(
contactInfo: ContactInfo,
): Promise<ContactIds> {
upsert: boolean,
): Promise<ContactIds | null> {
const chatId = contactInfo.ChatId();
// Check cache for chat id
@@ -77,10 +79,21 @@ export class ContactConversationService {
//
// Get or create a conversation for this inbox
//
const conversation = await this.conversationService.upsert({
const contactIds = {
id: cwContact.data.id,
sourceId: cwContact.sourceId,
});
};
let conversation: ConversationResult;
if (upsert) {
conversation = await this.conversationService.upsert(contactIds);
} else {
conversation = await this.conversationService.find(contactIds);
if (!conversation) {
// Nothing found, do not save it in cache
return null;
}
}
this.logger.debug(
`Using conversation for chat.id: ${chatId}, conversation.id: ${conversation.id}, contact.id: ${cwContact.sourceId}`,
);
@@ -94,11 +107,15 @@ export class ContactConversationService {
return ids;
}
public async ConversationByContact(
private async conversationByContact(
contactInfo: ContactInfo,
): Promise<Conversation> {
upsert: boolean,
): Promise<Conversation | null> {
const chatId = contactInfo.ChatId();
const ids = await this.upsertByContactInfo(contactInfo);
const ids = await this.getByContactInfo(contactInfo, upsert);
if (!ids) {
return null;
}
const conversation = new Conversation(
this.accountAPI,
this.config.accountId,
@@ -118,6 +135,26 @@ export class ContactConversationService {
return conversation;
}
/**
* Find or create if not exists conversation for the contact
*/
public async ConversationByContact(contactInfo: ContactInfo) {
const conversation = await this.conversationByContact(contactInfo, true);
if (!conversation) {
// Shouldn't happen, but for type safety
throw new Error('Conversation could not be created or found');
}
return conversation;
}
/**
* Find suitable conversation for the contact (based on filters)
* If nothing found - it doesn't create a new one
*/
public async FindConversationByContact(contactInfo: ContactInfo) {
return this.conversationByContact(contactInfo, false);
}
public ConversationById(conversationId: number): Conversation {
return new Conversation(
this.accountAPI,
@@ -0,0 +1,23 @@
import { sanitizeName } from '@waha/apps/chatwoot/client/ContactService';
describe('sanitizeName', () => {
it('should return the same name', () => {
const name = 'John Doe';
expect(sanitizeName(name)).toBe(name);
});
it('should return 254 symbols max', () => {
const name = 'a'.repeat(300);
expect(sanitizeName(name)).toBe('a'.repeat(255));
});
it('should remove bidi characters and trim the name', () => {
const name =
'‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪‏‪+123123‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏‬‏';
expect(sanitizeName(name)).toBe('+123123');
});
it('should not remove bidi characters if within limit', () => {
const name = 'محمد +123';
expect(sanitizeName(name)).toBe(name);
});
});
@@ -26,6 +26,20 @@ export enum AvatarUpdateMode {
ALWAYS,
}
export function sanitizeName(name: string) {
// 255 chars max
const limit = 255;
if (!name) {
return name;
}
if (name.length < limit) {
return name;
}
// remove only bidi controls
const clean = name.replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, '');
return clean.slice(0, 255).trim();
}
export class ContactService {
constructor(
private config: ChatWootAPIConfig,
@@ -139,6 +153,7 @@ export class ContactService {
chatId: string,
payload: public_contact_create_update_payload,
): Promise<ContactResponse> {
payload.name = sanitizeName(payload.name);
const contact = await this.inboxAPI.contacts.create({
inboxIdentifier: this.config.inboxIdentifier,
data: payload,
@@ -6,7 +6,6 @@ import {
} from '@waha/apps/chatwoot/client/interfaces';
import type { conversation } from '@figuro/chatwoot-sdk/dist/models/conversation';
import { ConversationSelector } from '@waha/apps/chatwoot/services/ConversationSelector';
import axios from 'axios';
import { ChatWootInboxNewAPI } from '@waha/apps/chatwoot/client/ChatWootInboxNewAPI';
export type ConversationResult = Pick<conversation, 'id' | 'account_id'>;
@@ -25,14 +24,20 @@ export class ConversationService {
private logger: ILogger,
) {}
private async find(contact: ContactIds): Promise<ConversationResult | null> {
public async find(contact: ContactIds): Promise<ConversationResult | null> {
const result: { payload: contact_conversations } =
(await this.accountAPI.contacts.listConversations({
accountId: this.config.accountId,
id: contact.id,
})) as any;
const conversations = result.payload;
return this.selector.select(conversations);
const conversation = this.selector.select(conversations);
if (conversation) {
this.logger.debug(
`Found existing conversation.id: ${conversation.id} for contact.id: ${contact.id}, contact.sourceId: ${contact.sourceId}`,
);
}
return conversation;
}
private async create(contact: ContactIds): Promise<ConversationResult> {
@@ -51,9 +56,6 @@ export class ConversationService {
if (!conversation) {
conversation = await this.create(contact);
}
this.logger.debug(
`Using conversation.id: ${conversation.id} for contact.id: ${contact.id}, contact.sourceId: ${contact.sourceId}`,
);
return conversation;
}
@@ -18,7 +18,6 @@ import { WAHAWebhookMessageAck } from '@waha/structures/webhooks.dto';
import { Job } from 'bullmq';
import { PinoLogger } from 'nestjs-pino';
import { ShouldMarkAsReadInChatWoot } from '@waha/apps/chatwoot/consumers/waha/message.ack.utils';
import { toCusFormat } from '@waha/core/utils/jids';
import { parseMessageIdSerialized } from '@waha/core/utils/ids';
import { MessageMappingService } from '@waha/apps/chatwoot/storage';
@@ -95,7 +94,16 @@ class MessageAckHandler {
this.locale,
);
const conversation =
await this.contactConversationService.ConversationByContact(contactInfo);
await this.contactConversationService.FindConversationByContact(
contactInfo,
);
if (!conversation) {
this.logger.debug(
`No suitable conversation found to mark as read for chat.id: ${payload.from}`,
);
return;
}
this.info.onConversationId(conversation.conversationId);
const sourceId = conversation.sourceId;
+1 -1
View File
@@ -6,7 +6,7 @@ export interface SValue {
generated: boolean;
}
function rand() {
export function rand() {
return crypto.randomUUID().toString().replace(/-/g, '');
}
@@ -4,6 +4,7 @@ import { EnginePayload } from '@waha/structures/webhooks.dto';
import { sleep } from '@waha/utils/promiseTimeout';
import { Logger } from 'pino';
import { Observable } from 'rxjs';
import { rand } from '@waha/core/auth/config';
/**
* Observable that listens to a gRPC stream and emits EnginePayload objects.
@@ -14,17 +15,35 @@ export class GowsEventStreamObservable extends Observable<EnginePayload> {
CLIENT_CLOSE_TIMEOUT = 1_000;
constructor(
private logger: Logger,
logger: Logger,
factory: () => {
client: grpc.Client;
stream: grpc.ClientReadableStream<messages.EventJson>;
},
) {
super((subscriber) => {
this.logger.debug('Creating grpc client and stream...');
logger.debug('Creating grpc stream...');
logger.setBindings({ id: rand() });
const { client, stream } = factory();
this._client = client;
let closed = false;
const cleanup = async (reason: string) => {
if (closed) {
return;
}
closed = true;
logger.debug({ reason }, 'Cancelling gRPC stream...');
try {
stream.cancel();
} catch (err) {
logger.warn({ err }, 'Failed to cancel gRPC stream');
}
await sleep(this.CLIENT_CLOSE_TIMEOUT);
};
stream.on('data', (raw) => {
const obj = raw.toObject();
obj.data = JSON.parse(obj.data);
@@ -32,18 +51,21 @@ export class GowsEventStreamObservable extends Observable<EnginePayload> {
});
stream.on('end', (...args) => {
this.logger.debug('Stream ended', args);
logger.debug('Stream ended', args);
subscriber?.complete();
subscriber = null;
void cleanup('end');
});
stream.on('error', async (err: any) => {
const CLIENT_CANCELLED_CODE = grpc.status.CANCELLED;
if (err.code === CLIENT_CANCELLED_CODE) {
this.logger.debug('Stream cancelled by client');
logger.debug('Stream cancelled by client');
await cleanup('cancelled');
return;
}
this.logger.error(err, 'Stream error');
logger.error(err, 'Stream error');
await cleanup('error');
// Give some time to node event loop to process the error
await sleep(100);
subscriber?.error(err);
@@ -51,14 +73,7 @@ export class GowsEventStreamObservable extends Observable<EnginePayload> {
});
return async () => {
this.logger.debug('Closing stream client...');
client.close();
await sleep(this.CLIENT_CLOSE_TIMEOUT);
this.logger.debug('Stream client closed');
this.logger.debug('Cancelling stream...');
stream.cancel();
this.logger.debug('Stream cancelled');
await cleanup('teardown');
};
});
}
+35
View File
@@ -0,0 +1,35 @@
import * as grpc from '@grpc/grpc-js';
import { messages } from '@waha/core/engines/gows/grpc/gows';
let messageServiceClient: messages.MessageServiceClient | null = null;
let eventStreamClient: messages.EventStreamClient | null = null;
export const MessageServiceClientSingleton = (
address: string,
credentials: grpc.ChannelCredentials,
options?: grpc.ChannelOptions,
): messages.MessageServiceClient => {
if (!messageServiceClient) {
messageServiceClient = new messages.MessageServiceClient(
address,
credentials,
options,
);
}
return messageServiceClient;
};
export const EventStreamClientSingleton = (
address: string,
credentials: grpc.ChannelCredentials,
options?: grpc.ChannelOptions,
): messages.EventStreamClient => {
if (!eventStreamClient) {
eventStreamClient = new messages.EventStreamClient(
address,
credentials,
options,
);
}
return eventStreamClient;
};
+24 -7
View File
@@ -171,6 +171,10 @@ import {
isLabelChatAddedEvent,
isLabelUpsertEvent,
} from './labels.gows';
import {
EventStreamClientSingleton,
MessageServiceClientSingleton,
} from '@waha/core/engines/gows/clients';
import esm from '@waha/vendor/esm';
import { IsEditedMessage } from '@waha/core/utils/pwa';
import MessageServiceClient = messages.MessageServiceClient;
@@ -272,7 +276,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
}),
});
this.client = new MessageServiceClient(
this.client = MessageServiceClientSingleton(
this.engineConfig.connection,
grpc.credentials.createInsecure(),
gRPCClientConfig,
@@ -302,7 +306,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
this.stream$ = new GowsEventStreamObservable(
this.loggerBuilder.child({ grpc: 'stream' }),
() => {
const client = new messages.EventStreamClient(
const client = EventStreamClientSingleton(
this.engineConfig.connection,
grpc.credentials.createInsecure(),
gRPCClientConfig,
@@ -701,7 +705,6 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
this.status = WAHASessionStatus.STOPPED;
this.events?.stop();
this.stopEvents();
this.client?.close();
this.mediaManager.close();
}
@@ -2369,6 +2372,8 @@ export class GOWSEngineMediaProcessor implements IMediaEngineProcessor<any> {
}
async getMediaBuffer(message: any): Promise<Buffer | null> {
const mediaDownloadTimeoutMs = 600_000; // 10 minutes
const data = JSON.stringify(message.Message);
const request = new messages.DownloadMediaRequest({
// double "session" it's not a mistake here
@@ -2377,11 +2382,23 @@ export class GOWSEngineMediaProcessor implements IMediaEngineProcessor<any> {
jid: message.Info.Chat,
messageId: message.Info.ID,
});
const response = await promisify(this.session.client.DownloadMedia)(
request,
const opts = {
deadline: new Date(Date.now() + mediaDownloadTimeoutMs),
};
const call = promisify(
this.session.client.DownloadMedia.bind(this.session.client),
);
const obj = response.toObject();
return Buffer.from(obj.content);
try {
const response = await call(request, opts);
const obj = response.toObject();
return Buffer.from(obj.content);
} catch (err) {
if (err?.code === grpc.status.DEADLINE_EXCEEDED) {
err.message = `DownloadMedia timed out after ${mediaDownloadTimeoutMs}ms for message '${message?.Info?.ID}'`;
}
throw err;
}
}
getFilename(message: any): string | null {
+14 -1
View File
@@ -1,6 +1,19 @@
import { ApiProperty } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import { IsArray, IsNumber, IsOptional, IsString } from 'class-validator';
import { IsArray, IsNumber, IsOptional, IsString, Min } from 'class-validator';
export class CpuProfileQuery {
@Type(() => Number)
@IsNumber()
@Min(1)
@ApiProperty({
description: 'How many seconds to sample CPU',
example: 30,
required: false,
default: 30,
})
seconds: number = 30;
}
export class BrowserTraceQuery {
@Type(() => Number)
+1 -1
View File
@@ -30,7 +30,7 @@ export function getWAHAVersion(): WAHAVersion {
}
export const VERSION: WAHAEnvironment = {
version: '2025.11.2',
version: '2025.11.3',
engine: getEngineName(),
tier: getWAHAVersion(),
browser:
+2 -2
View File
@@ -2,11 +2,11 @@
"waha": {
"gows": {
"repo": "devlikeapro/gows",
"ref": "v1.0.21"
"ref": "v1.0.23"
},
"dashboard": {
"repo": "devlikeapro/dashboard",
"ref": "3861e0854f4dba106e3e223e6f5df15d58b61949"
"ref": "d982212d20191adab7065216cad45ff064b483d8"
}
}
}
+45 -25
View File
@@ -5,9 +5,9 @@ __metadata:
version: 6
cacheKey: 8
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-11-07":
version: 7.0.0-rc.6
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=e828866d7936785b054e16f360c32115f118f291"
"@adiwajshing/baileys@github:devlikeapro/Baileys#fork-master-2025-11-21":
version: 7.0.0-rc.9
resolution: "@adiwajshing/baileys@https://github.com/devlikeapro/Baileys.git#commit=4fb1d817fbc9e25c8011dcd0bd0836b11a340c5a"
dependencies:
"@cacheable/node-cache": ^1.4.0
"@hapi/boom": ^9.1.3
@@ -31,7 +31,7 @@ __metadata:
optional: true
link-preview-js:
optional: true
checksum: 0a02bc71fe13e998047f10e205126cca978ffde85a50fabc8ccf25c79a3ff6baecc857a395956e6c37b10abbeb9e390e4fcbc870ea11e3a22224cbc8c562c41e
checksum: b355cd7012afb96ae79d4d7debd3a888ed844d3ddef0ba83b9cd965f3d901bf2d42630be93064e0abcb1abd842f62d89c09cc6f7545ed3086d14422f789a80ec
languageName: node
linkType: hard
@@ -1290,27 +1290,27 @@ __metadata:
languageName: node
linkType: hard
"@grpc/grpc-js@npm:^1.13.4":
version: 1.13.4
resolution: "@grpc/grpc-js@npm:1.13.4"
"@grpc/grpc-js@npm:^1.14.1":
version: 1.14.1
resolution: "@grpc/grpc-js@npm:1.14.1"
dependencies:
"@grpc/proto-loader": ^0.7.13
"@grpc/proto-loader": ^0.8.0
"@js-sdsl/ordered-map": ^4.4.2
checksum: fe5db84bbbcd07cc1b68d1683b7fbe9cfcc5c3a60655ecc17fb3e1cd2adc4c1ce891b15e6e9a9c2140f6891def6f93b509a60d2bce253d13b317f9136e968451
checksum: 3f208c23cc985789934d806045599ad3bfa1b6fd9877151cf9af423b4d708cbb3b0cb1347a147061c6ed36470958fd522fbefbf6ae4ca8246f0860bd647f0e5e
languageName: node
linkType: hard
"@grpc/proto-loader@npm:^0.7.13":
version: 0.7.15
resolution: "@grpc/proto-loader@npm:0.7.15"
"@grpc/proto-loader@npm:^0.8.0":
version: 0.8.0
resolution: "@grpc/proto-loader@npm:0.8.0"
dependencies:
lodash.camelcase: ^4.3.0
long: ^5.0.0
protobufjs: ^7.2.5
protobufjs: ^7.5.3
yargs: ^17.7.2
bin:
proto-loader-gen-types: build/bin/proto-loader-gen-types.js
checksum: 9f19f4c611a17cd33aec0d6e3686a76696495f40593f7c284933c4b7877f58dfa5a225ddc20705860a632311f4dc0d143cb6a0da7b51b6f5ffd7de26938df308
checksum: 97570e2e8c29a35b999fa929acad506765e6752d3219764825fecc0ab632492b1ac2e4dd4c0a96cc2e01754d99bfa838dff0729c6608a02f7b027fd19bc1d1e4
languageName: node
linkType: hard
@@ -7279,10 +7279,10 @@ __metadata:
languageName: node
linkType: hard
"google-protobuf@npm:^3.21.4":
version: 3.21.4
resolution: "google-protobuf@npm:3.21.4"
checksum: 048fa2cb579f5f88c977774b2ae36851807379d9329a6895fe3685df69ba6c927e2ff463d08d5eecd56becd9c65bca406f34f90e27984a3077e8629bb3a2a766
"google-protobuf@npm:^4.0.1":
version: 4.0.1
resolution: "google-protobuf@npm:4.0.1"
checksum: d6ed3007b121ac28dbe9a686bdcc26ba4aba8bc41bd43bbaf59c2cbad96eba4d56338b9da56e8006fa89922eb5b15cb5c79f40b82d03ac39e006c9163435ad4b
languageName: node
linkType: hard
@@ -10456,7 +10456,7 @@ __metadata:
languageName: node
linkType: hard
"protobufjs@npm:^7.2.4, protobufjs@npm:^7.2.5":
"protobufjs@npm:^7.2.4":
version: 7.5.3
resolution: "protobufjs@npm:7.5.3"
dependencies:
@@ -10476,6 +10476,26 @@ __metadata:
languageName: node
linkType: hard
"protobufjs@npm:^7.5.3":
version: 7.5.4
resolution: "protobufjs@npm:7.5.4"
dependencies:
"@protobufjs/aspromise": ^1.1.2
"@protobufjs/base64": ^1.1.2
"@protobufjs/codegen": ^2.0.4
"@protobufjs/eventemitter": ^1.1.0
"@protobufjs/fetch": ^1.1.0
"@protobufjs/float": ^1.0.2
"@protobufjs/inquire": ^1.1.0
"@protobufjs/path": ^1.1.2
"@protobufjs/pool": ^1.1.0
"@protobufjs/utf8": ^1.1.0
"@types/node": ">=13.7.0"
long: ^5.0.0
checksum: 53bf83b9a726b05d43da35bb990dba7536759787dccea9a67b8f31be9df470ba17f1f1b982ca19956cfc7726f3ec7e0e883ca4ad93b5ec753cc025a637fc704f
languageName: node
linkType: hard
"protoc-gen-ts@npm:^0.8.7":
version: 0.8.7
resolution: "protoc-gen-ts@npm:0.8.7"
@@ -12532,7 +12552,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "waha@workspace:."
dependencies:
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-11-07"
"@adiwajshing/baileys": "github:devlikeapro/Baileys#fork-master-2025-11-21"
"@adiwajshing/keyed-db": ^0.2.4
"@aws-sdk/client-s3": ^3.633.0
"@aws-sdk/s3-request-presigner": ^3.633.0
@@ -12540,8 +12560,8 @@ __metadata:
"@bull-board/express": ^6.9.1
"@bull-board/nestjs": ^6.9.1
"@figuro/chatwoot-sdk": ^1.1.17
"@grpc/grpc-js": ^1.13.4
"@grpc/proto-loader": ^0.7.13
"@grpc/grpc-js": ^1.14.1
"@grpc/proto-loader": ^0.8.0
"@liaoliaots/nestjs-redis": ^9
"@nestjs/axios": ^3.0.2
"@nestjs/bullmq": ^11.0.2
@@ -12589,7 +12609,7 @@ __metadata:
express-basic-auth: ^1.2.1
file-type: 16.5.4
fs-extra: ^11.2.0
google-protobuf: ^3.21.4
google-protobuf: ^4.0.1
grpc-tools: ^1.13.0
https-proxy-agent: ^7.0.0
ical.js: ^2.2.1
@@ -12739,7 +12759,7 @@ __metadata:
"whatsapp-web.js@github:devlikeapro/whatsapp-web.js#fork-main-2025-11-05":
version: 1.34.2
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=c84b4af4dfd01f326d37f4de6acd7bebc06496d0"
resolution: "whatsapp-web.js@https://github.com/devlikeapro/whatsapp-web.js.git#commit=06c56b6a693d438e38793cec150c2890ca59910f"
dependencies:
"@pedroslopez/moduleraid": ^5.0.2
archiver: ^5.3.1
@@ -12757,7 +12777,7 @@ __metadata:
optional: true
unzipper:
optional: true
checksum: d9d615d29ba14f6113080a19d8f7e1396ea7dde3cbe4983db04e8df512483198c3f73236e9e8c366afb035ee700bd5718d72bc18ee01caeb7cd86bcadfdbb056
checksum: 46971900f209cb9988a8386ce13d9d082d7133711b1e6c38e1880684a70c1eda407be3c6fe45cd2526160efd47c2780b6b55500592ffc2b8c784f5e6c7d54670
languageName: node
linkType: hard