From 2fb63180118057efee5639d0dac1bbd67d6a3e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Souza?= Date: Fri, 27 Dec 2024 10:40:04 -0300 Subject: [PATCH 01/27] feat: updates api evolution for docker --- .dockerignore | 2 ++ Docker/scripts/deploy_database.sh | 27 ++++++++++++++++++++------- Dockerfile | 2 +- package.json | 8 +++++--- src/api/services/monitor.service.ts | 17 +++++++++-------- src/api/types/wa.types.ts | 9 ++++++++- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/.dockerignore b/.dockerignore index 0d406464d..eb2115325 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,7 @@ .git *Dockerfile* *docker-compose* +package-lock.json +.env node_modules dist \ No newline at end of file diff --git a/Docker/scripts/deploy_database.sh b/Docker/scripts/deploy_database.sh index fde46d120..4ee735ee7 100755 --- a/Docker/scripts/deploy_database.sh +++ b/Docker/scripts/deploy_database.sh @@ -1,24 +1,36 @@ #!/bin/bash +# Fonte das variáveis de ambiente source ./Docker/scripts/env_functions.sh +# Carregar variáveis de ambiente se não estiver no ambiente Docker if [ "$DOCKER_ENV" != "true" ]; then export_env_vars fi +# Verificar se o banco de dados é PostgreSQL ou MySQL if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]]; then export DATABASE_URL echo "Deploying migrations for $DATABASE_PROVIDER" echo "Database URL: $DATABASE_URL" - # rm -rf ./prisma/migrations - # cp -r ./prisma/$DATABASE_PROVIDER-migrations ./prisma/migrations - npm run db:deploy - if [ $? -ne 0 ]; then - echo "Migration failed" - exit 1 + + # Verificar se há migrações pendentes com Prisma + MIGRATION_STATUS=$(npx prisma migrate status) + + if echo "$MIGRATION_STATUS" | grep -q "Pending"; then + echo "Migrações pendentes encontradas. Executando deploy..." + npm run db:deploy # Aplica as migrações pendentes + if [ $? -ne 0 ]; then + echo "Migration failed" + exit 1 + else + echo "Migration succeeded" + fi else - echo "Migration succeeded" + echo "Nenhuma migração pendente. Pulando deploy." fi + + # Gerar o Prisma Client após o deploy npm run db:generate if [ $? -ne 0 ]; then echo "Prisma generate failed" @@ -26,6 +38,7 @@ if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]] else echo "Prisma generate succeeded" fi + else echo "Error: Database provider $DATABASE_PROVIDER invalid." exit 1 diff --git a/Dockerfile b/Dockerfile index 4c99317d4..12067e12a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM node:20-alpine AS builder RUN apk update && \ - apk add git ffmpeg wget curl bash + apk add --no-cache git ffmpeg wget curl bash openssl LABEL version="2.2.0" description="Api to control whatsapp features through http requests." LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" diff --git a/package.json b/package.json index f7e77194e..af95f7927 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "db:generate": "node runWithProvider.js \"npx prisma generate --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"", "db:deploy": "node runWithProvider.js \"rm -rf ./prisma/migrations && cp -r ./prisma/DATABASE_PROVIDER-migrations ./prisma/migrations && npx prisma migrate deploy --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"", "db:studio": "node runWithProvider.js \"npx prisma studio --schema ./prisma/DATABASE_PROVIDER-schema.prisma\"", - "db:migrate:dev": "node runWithProvider.js \"rm -rf ./prisma/migrations && cp -r ./prisma/DATABASE_PROVIDER-migrations ./prisma/migrations && npx prisma migrate dev --schema ./prisma/DATABASE_PROVIDER-schema.prisma && cp -r ./prisma/migrations/* ./prisma/DATABASE_PROVIDER-migrations\"" + "db:migrate:dev": "node runWithProvider.js \"rm -rf ./prisma/migrations && cp -r ./prisma/DATABASE_PROVIDER-migrations ./prisma/migrations && npx prisma migrate dev --schema ./prisma/DATABASE_PROVIDER-schema.prisma && cp -r ./prisma/migrations/* ./prisma/DATABASE_PROVIDER-migrations\"", + "docker:build": "docker build -t joaovictorsouza/evolution-api:latest .", + "docker:push": "docker push joaovictorsouza/evolution-api:latest" }, "repository": { "type": "git", @@ -51,7 +53,7 @@ "@ffmpeg-installer/ffmpeg": "^1.1.0", "@figuro/chatwoot-sdk": "^1.1.16", "@hapi/boom": "^10.0.1", - "@prisma/client": "^5.15.0", + "@prisma/client": "^6.1.0", "@sentry/node": "^8.28.0", "amqplib": "^0.10.3", "axios": "^1.6.5", @@ -82,7 +84,7 @@ "openai": "^4.52.7", "pg": "^8.11.3", "pino": "^8.11.0", - "prisma": "^5.15.0", + "prisma": "^6.1.0", "pusher": "^5.2.0", "qrcode": "^1.5.1", "qrcode-terminal": "^0.12.0", diff --git a/src/api/services/monitor.service.ts b/src/api/services/monitor.service.ts index c69e4fca5..cd2025063 100644 --- a/src/api/services/monitor.service.ts +++ b/src/api/services/monitor.service.ts @@ -72,14 +72,15 @@ export class WAMonitoringService { const clientName = this.configService.get('DATABASE').CONNECTION.CLIENT_NAME; - const where = instanceNames && instanceNames.length > 0 - ? { - name: { - in: instanceNames, - }, - clientName, - } - : { clientName }; + const where = + instanceNames && instanceNames.length > 0 + ? { + name: { + in: instanceNames, + }, + clientName, + } + : { clientName }; const instances = await this.prismaRepository.instance.findMany({ where, diff --git a/src/api/types/wa.types.ts b/src/api/types/wa.types.ts index 72c183b23..472b37af2 100644 --- a/src/api/types/wa.types.ts +++ b/src/api/types/wa.types.ts @@ -131,7 +131,14 @@ export declare namespace wa { export type StatusMessage = 'ERROR' | 'PENDING' | 'SERVER_ACK' | 'DELIVERY_ACK' | 'READ' | 'DELETED' | 'PLAYED'; } -export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage', 'ptvMessage']; +export const TypeMediaMessage = [ + 'imageMessage', + 'documentMessage', + 'audioMessage', + 'videoMessage', + 'stickerMessage', + 'ptvMessage', +]; export const MessageSubtype = [ 'ephemeralMessage', From 79b1c6bb1c5028a24ed4903580f0627c66edef8e Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Fri, 31 Jan 2025 17:38:42 -0300 Subject: [PATCH 02/27] feat: Add configurable file/cache storage for authentication state - Update Baileys package to version 6.7.10 - Implement conditional storage mechanism for authentication state - Add support for file-based or Redis cache storage based on environment configuration - Re-enable previously commented out file handling utility functions --- package-lock.json | 4 +- src/utils/use-multi-file-auth-state-prisma.ts | 60 +++++++++++-------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2396888d1..6169f7eeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4752,8 +4752,8 @@ "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" }, "node_modules/baileys": { - "version": "6.7.9", - "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#2140e16a9214067bf4cd408e88c231c24636a9e9", + "version": "6.7.10", + "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#3d42781a00eb6d1b0f31f825a65b5e75708b9a89", "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", "@hapi/boom": "^9.1.3", diff --git a/src/utils/use-multi-file-auth-state-prisma.ts b/src/utils/use-multi-file-auth-state-prisma.ts index 02f96f151..e16dc8b08 100644 --- a/src/utils/use-multi-file-auth-state-prisma.ts +++ b/src/utils/use-multi-file-auth-state-prisma.ts @@ -5,14 +5,14 @@ import { AuthenticationState, BufferJSON, initAuthCreds, WAProto as proto } from import fs from 'fs/promises'; import path from 'path'; -// const fixFileName = (file: string): string | undefined => { -// if (!file) { -// return undefined; -// } -// const replacedSlash = file.replace(/\//g, '__'); -// const replacedColon = replacedSlash.replace(/:/g, '-'); -// return replacedColon; -// }; +const fixFileName = (file: string): string | undefined => { + if (!file) { + return undefined; + } + const replacedSlash = file.replace(/\//g, '__'); + const replacedColon = replacedSlash.replace(/:/g, '-'); + return replacedColon; +}; export async function keyExists(sessionId: string): Promise { try { @@ -63,14 +63,14 @@ async function deleteAuthKey(sessionId: string): Promise { } } -// async function fileExists(file: string): Promise { -// try { -// const stat = await fs.stat(file); -// if (stat.isFile()) return true; -// } catch (error) { -// return; -// } -// } +async function fileExists(file: string): Promise { + try { + const stat = await fs.stat(file); + if (stat.isFile()) return true; + } catch (error) { + return; + } +} export default async function useMultiFileAuthStatePrisma( sessionId: string, @@ -80,16 +80,19 @@ export default async function useMultiFileAuthStatePrisma( saveCreds: () => Promise; }> { const localFolder = path.join(INSTANCE_DIR, sessionId); - // const localFile = (key: string) => path.join(localFolder, fixFileName(key) + '.json'); + const localFile = (key: string) => path.join(localFolder, fixFileName(key) + '.json'); await fs.mkdir(localFolder, { recursive: true }); async function writeData(data: any, key: string): Promise { const dataString = JSON.stringify(data, BufferJSON.replacer); if (key != 'creds') { - return await cache.hSet(sessionId, key, data); - // await fs.writeFile(localFile(key), dataString); - // return; + if (process.env.CACHE_REDIS_ENABLED === 'true') { + return await cache.hSet(sessionId, key, data); + } else { + await fs.writeFile(localFile(key), dataString); + return; + } } await saveKey(sessionId, dataString); return; @@ -100,9 +103,13 @@ export default async function useMultiFileAuthStatePrisma( let rawData; if (key != 'creds') { - return await cache.hGet(sessionId, key); - // if (!(await fileExists(localFile(key)))) return null; - // rawData = await fs.readFile(localFile(key), { encoding: 'utf-8' }); + if (process.env.CACHE_REDIS_ENABLED === 'true') { + return await cache.hGet(sessionId, key); + } else { + if (!(await fileExists(localFile(key)))) return null; + rawData = await fs.readFile(localFile(key), { encoding: 'utf-8' }); + return JSON.parse(rawData, BufferJSON.reviver); + } } else { rawData = await getAuthKey(sessionId); } @@ -117,8 +124,11 @@ export default async function useMultiFileAuthStatePrisma( async function removeData(key: string): Promise { try { if (key != 'creds') { - return await cache.hDelete(sessionId, key); - // await fs.unlink(localFile(key)); + if (process.env.CACHE_REDIS_ENABLED === 'true') { + return await cache.hDelete(sessionId, key); + } else { + await fs.unlink(localFile(key)); + } } else { await deleteAuthKey(sessionId); } From f8f1cbf4a2e1f5e4b410213279e0e6bb7ba0bda0 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Fri, 31 Jan 2025 17:44:44 -0300 Subject: [PATCH 03/27] fix: Disable group metadata caching in Baileys service - Remove group metadata caching mechanisms - Modify group-related cache update methods - Simplify group metadata retrieval process --- CHANGELOG.md | 7 +++++++ .../whatsapp/whatsapp.baileys.service.ts | 21 ++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 397ce2e6e..53119159f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 2.2.3 (develop) + +### Fixed + +* Fix cache in local file system +* Update Baileys Version + # 2.2.2 (2025-01-31 06:55) ### Features diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 2de394348..fd8e8e396 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -668,7 +668,7 @@ export class BaileysStartupService extends ChannelStartupService { shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { return this.historySyncNotification(msg); }, - cachedGroupMetadata: this.getGroupMetadataCache, + // cachedGroupMetadata: this.getGroupMetadataCache, userDevicesCache: this.userDevicesCache, transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 }, patchMessageBeforeSending(message) { @@ -1562,11 +1562,11 @@ export class BaileysStartupService extends ChannelStartupService { 'groups.update': (groupMetadataUpdate: Partial[]) => { this.sendDataWebhook(Events.GROUPS_UPDATE, groupMetadataUpdate); - groupMetadataUpdate.forEach((group) => { - if (isJidGroup(group.id)) { - this.updateGroupMetadataCache(group.id); - } - }); + // groupMetadataUpdate.forEach((group) => { + // if (isJidGroup(group.id)) { + // this.updateGroupMetadataCache(group.id); + // } + // }); }, 'group-participants.update': (participantsUpdate: { @@ -1576,7 +1576,7 @@ export class BaileysStartupService extends ChannelStartupService { }) => { this.sendDataWebhook(Events.GROUP_PARTICIPANTS_UPDATE, participantsUpdate); - this.updateGroupMetadataCache(participantsUpdate.id); + // this.updateGroupMetadataCache(participantsUpdate.id); }, }; @@ -2160,9 +2160,10 @@ export class BaileysStartupService extends ChannelStartupService { if (isJidGroup(sender)) { let group; try { - const cache = this.configService.get('CACHE'); - if (!cache.REDIS.ENABLED && !cache.LOCAL.ENABLED) group = await this.findGroup({ groupJid: sender }, 'inner'); - else group = await this.getGroupMetadataCache(sender); + // const cache = this.configService.get('CACHE'); + // if (!cache.REDIS.ENABLED && !cache.LOCAL.ENABLED) group = await this.findGroup({ groupJid: sender }, 'inner'); + // else group = await this.getGroupMetadataCache(sender); + group = await this.findGroup({ groupJid: sender }, 'inner'); } catch (error) { throw new NotFoundException('Group not found'); } From 7ea46a05cac30104e80780c02772feb01156bad0 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Fri, 31 Jan 2025 17:45:09 -0300 Subject: [PATCH 04/27] version: 2.2.3 --- Dockerfile | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 370cc7f7d..ca61b39a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM node:20-alpine AS builder RUN apk update && \ apk add git ffmpeg wget curl bash openssl -LABEL version="2.2.2" description="Api to control whatsapp features through http requests." +LABEL version="2.2.3" description="Api to control whatsapp features through http requests." LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" LABEL contact="contato@atendai.com" diff --git a/package.json b/package.json index d2fcf50a5..7e948028a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "evolution-api", - "version": "2.2.2", + "version": "2.2.3", "description": "Rest api for communication with WhatsApp", "main": "./dist/main.js", "type": "commonjs", From c1494ca03515cbfeea52ca89752930865984b9d5 Mon Sep 17 00:00:00 2001 From: Aditya Nandwana Date: Sat, 1 Feb 2025 16:04:35 +0530 Subject: [PATCH 05/27] Refactor logical message deletion in BaileysStartupService --- .../channel/whatsapp/whatsapp.baileys.service.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 2de394348..a5602ab6d 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -3551,25 +3551,31 @@ export class BaileysStartupService extends ChannelStartupService { const messageId = response.message?.protocolMessage?.key?.id; if (messageId) { const isLogicalDeleted = configService.get('DATABASE').DELETE_DATA.LOGICAL_MESSAGE_DELETE; - let message = await this.prismaRepository.message.findUnique({ - where: { id: messageId }, + let message = await this.prismaRepository.message.findFirst({ + where: { + key: { + path: ['id'], + equals: messageId, + }, + }, }); if (isLogicalDeleted) { if (!message) return response; const existingKey = typeof message?.key === 'object' && message.key !== null ? message.key : {}; message = await this.prismaRepository.message.update({ - where: { id: messageId }, + where: { id: message.id }, data: { key: { ...existingKey, deleted: true, }, + status: 'DELETED', }, }); } else { await this.prismaRepository.message.deleteMany({ where: { - id: messageId, + id: message.id, }, }); } @@ -3578,7 +3584,7 @@ export class BaileysStartupService extends ChannelStartupService { instanceId: message.instanceId, key: message.key, messageType: message.messageType, - status: message.status, + status: 'DELETED', source: message.source, messageTimestamp: message.messageTimestamp, pushName: message.pushName, From fc84e0f32723c17103c30de7a59c2e64b0a42907 Mon Sep 17 00:00:00 2001 From: Toni Moreira Date: Sat, 1 Feb 2025 11:47:50 -0300 Subject: [PATCH 06/27] fix: dify truncated messages --- .../chatbot/dify/services/dify.service.ts | 66 +++++++------------ 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/src/api/integrations/chatbot/dify/services/dify.service.ts b/src/api/integrations/chatbot/dify/services/dify.service.ts index c60782d79..348ee70c5 100644 --- a/src/api/integrations/chatbot/dify/services/dify.service.ts +++ b/src/api/integrations/chatbot/dify/services/dify.service.ts @@ -224,63 +224,43 @@ export class DifyService { headers: { Authorization: `Bearer ${dify.apiKey}`, }, - responseType: 'stream', }); let conversationId; let answer = ''; - const stream = response.data; - const reader = new Readable().wrap(stream); + const data = response.data.replaceAll('data: ', ''); - reader.on('data', (chunk) => { - const data = chunk.toString().replace(/data:\s*/g, ''); + const events = data.split('\n').filter((line) => line.trim() !== ''); - if (data.trim() === '' || !data.startsWith('{')) { - return; - } - - try { - const events = data.split('\n').filter((line) => line.trim() !== ''); + for (const eventString of events) { + if (eventString.trim().startsWith('{')) { + const event = JSON.parse(eventString); - for (const eventString of events) { - if (eventString.trim().startsWith('{')) { - const event = JSON.parse(eventString); - - if (event?.event === 'agent_message') { - console.log('event:', event); - conversationId = conversationId ?? event?.conversation_id; - answer += event?.answer; - } - } + if (event?.event === 'agent_message') { + console.log('event:', event); + conversationId = conversationId ?? event?.conversation_id; + answer += event?.answer; } - } catch (error) { - console.error('Error parsing stream data:', error); } - }); - - reader.on('end', async () => { - if (instance.integration === Integration.WHATSAPP_BAILEYS) - await instance.client.sendPresenceUpdate('paused', remoteJid); + } - const message = answer; + if (instance.integration === Integration.WHATSAPP_BAILEYS) + await instance.client.sendPresenceUpdate('paused', remoteJid); - await this.sendMessageWhatsApp(instance, remoteJid, message, settings); + const message = answer; - await this.prismaRepository.integrationSession.update({ - where: { - id: session.id, - }, - data: { - status: 'opened', - awaitUser: true, - sessionId: conversationId, - }, - }); - }); + await this.sendMessageWhatsApp(instance, remoteJid, message, settings); - reader.on('error', (error) => { - console.error('Error reading stream:', error); + await this.prismaRepository.integrationSession.update({ + where: { + id: session.id, + }, + data: { + status: 'opened', + awaitUser: true, + sessionId: conversationId, + }, }); return; From b09638600e871c018c94d66951e6f7ac0d90ee3f Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Sat, 1 Feb 2025 15:39:14 -0300 Subject: [PATCH 07/27] chore: Upgrade Baileys to version 6.7.12 - Update Baileys package to latest version - Bump package version to 2.2.3 --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6169f7eeb..29c61422c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "evolution-api", - "version": "2.2.2", + "version": "2.2.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "evolution-api", - "version": "2.2.2", + "version": "2.2.3", "license": "Apache-2.0", "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", @@ -4752,8 +4752,8 @@ "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" }, "node_modules/baileys": { - "version": "6.7.10", - "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#3d42781a00eb6d1b0f31f825a65b5e75708b9a89", + "version": "6.7.12", + "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#ce92d5d32f1174f050d2bba8fd637dc6e45faafa", "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", "@hapi/boom": "^9.1.3", From 4a5d7a91e22147cd56194ff7129e3fb3a3bf26ec Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Sun, 2 Feb 2025 11:39:45 -0300 Subject: [PATCH 08/27] chore: Update Baileys package to latest commit hash --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 29c61422c..83bd4d16c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4753,7 +4753,7 @@ }, "node_modules/baileys": { "version": "6.7.12", - "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#ce92d5d32f1174f050d2bba8fd637dc6e45faafa", + "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#2c69f65d4b6c4e779d6e3d2c0c32689a5425df95", "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", "@hapi/boom": "^9.1.3", From 3c2ea5c67c3f07a24812e64f2da0c942fb91b117 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Sun, 2 Feb 2025 16:42:17 -0300 Subject: [PATCH 09/27] feat: Re-enable group metadata caching in Baileys service - Restore group metadata caching mechanisms - Uncomment cache-related methods for group updates and participants - Implement conditional group metadata retrieval based on cache configuration --- .../whatsapp/whatsapp.baileys.service.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index cd6fac51f..10feb7ce1 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -668,7 +668,7 @@ export class BaileysStartupService extends ChannelStartupService { shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { return this.historySyncNotification(msg); }, - // cachedGroupMetadata: this.getGroupMetadataCache, + cachedGroupMetadata: this.getGroupMetadataCache, userDevicesCache: this.userDevicesCache, transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 }, patchMessageBeforeSending(message) { @@ -1562,11 +1562,11 @@ export class BaileysStartupService extends ChannelStartupService { 'groups.update': (groupMetadataUpdate: Partial[]) => { this.sendDataWebhook(Events.GROUPS_UPDATE, groupMetadataUpdate); - // groupMetadataUpdate.forEach((group) => { - // if (isJidGroup(group.id)) { - // this.updateGroupMetadataCache(group.id); - // } - // }); + groupMetadataUpdate.forEach((group) => { + if (isJidGroup(group.id)) { + this.updateGroupMetadataCache(group.id); + } + }); }, 'group-participants.update': (participantsUpdate: { @@ -1576,7 +1576,7 @@ export class BaileysStartupService extends ChannelStartupService { }) => { this.sendDataWebhook(Events.GROUP_PARTICIPANTS_UPDATE, participantsUpdate); - // this.updateGroupMetadataCache(participantsUpdate.id); + this.updateGroupMetadataCache(participantsUpdate.id); }, }; @@ -2160,10 +2160,10 @@ export class BaileysStartupService extends ChannelStartupService { if (isJidGroup(sender)) { let group; try { - // const cache = this.configService.get('CACHE'); - // if (!cache.REDIS.ENABLED && !cache.LOCAL.ENABLED) group = await this.findGroup({ groupJid: sender }, 'inner'); - // else group = await this.getGroupMetadataCache(sender); - group = await this.findGroup({ groupJid: sender }, 'inner'); + const cache = this.configService.get('CACHE'); + if (!cache.REDIS.ENABLED && !cache.LOCAL.ENABLED) group = await this.findGroup({ groupJid: sender }, 'inner'); + else group = await this.getGroupMetadataCache(sender); + // group = await this.findGroup({ groupJid: sender }, 'inner'); } catch (error) { throw new NotFoundException('Group not found'); } From 96821f5d9ab301d4be6319a5947c999049af48e2 Mon Sep 17 00:00:00 2001 From: Aditya Nandwana Date: Mon, 3 Feb 2025 11:43:53 +0530 Subject: [PATCH 10/27] Refactor BaileysStartupService updateMessage method --- .../whatsapp/whatsapp.baileys.service.ts | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index a5602ab6d..2bb01b4cb 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -3888,7 +3888,7 @@ export class BaileysStartupService extends ChannelStartupService { } public async updateMessage(data: UpdateMessageDto) { - const jid = createJid(data.number); + const jid = this.createJid(data.number); const options = await this.formatUpdateMessage(data); @@ -3898,13 +3898,72 @@ export class BaileysStartupService extends ChannelStartupService { } try { - return await this.client.sendMessage(jid, { + const response = await this.client.sendMessage(jid, { ...(options as any), edit: data.key, }); + if (response) { + const messageId = response.message?.protocolMessage?.key?.id; + if (messageId) { + let message = await this.prismaRepository.message.findFirst({ + where: { + key: { + path: ['id'], + equals: messageId, + }, + }, + }); + if (!message) throw new NotFoundException('Message not found'); + + if (!(message.key.valueOf() as any).fromMe) { + new BadRequestException('You cannot edit others messages'); + } + if ((message.key.valueOf() as any)?.deleted) { + new BadRequestException('You cannot edit deleted messages'); + } + + const updateMessage = this.prepareMessage({ ...response }); + message = await this.prismaRepository.message.update({ + where: { id: message.id }, + data: { + message: { + ...updateMessage?.message?.[updateMessage.messageType]?.editedMessage, + }, + status: 'EDITED', + }, + }); + const messageUpdate: any = { + messageId: message.id, + keyId: messageId, + remoteJid: response.key.remoteJid, + fromMe: response.key.fromMe, + participant: response.key?.remoteJid, + status: 'EDITED', + instanceId: this.instanceId, + }; + await this.prismaRepository.messageUpdate.create({ + data: messageUpdate, + }); + + this.sendDataWebhook(Events.MESSAGES_EDITED, { + id: message.id, + instanceId: message.instanceId, + key: message.key, + messageType: message.messageType, + status: 'EDITED', + source: message.source, + messageTimestamp: message.messageTimestamp, + pushName: message.pushName, + participant: message.participant, + message: message.message, + }); + } + } + + return response; } catch (error) { this.logger.error(error); - throw new BadRequestException(error.toString()); + throw error; } } From 4137984b5dab1189507d177526958c7cb9b39ad3 Mon Sep 17 00:00:00 2001 From: Aditya Nandwana Date: Mon, 3 Feb 2025 11:44:41 +0530 Subject: [PATCH 11/27] Refactor message deletion in BaileysStartupService --- .../channel/whatsapp/whatsapp.baileys.service.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 2bb01b4cb..c53e2d4ce 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -3572,6 +3572,18 @@ export class BaileysStartupService extends ChannelStartupService { status: 'DELETED', }, }); + const messageUpdate: any = { + messageId: message.id, + keyId: messageId, + remoteJid: response.key.remoteJid, + fromMe: response.key.fromMe, + participant: response.key?.remoteJid, + status: 'DELETED', + instanceId: this.instanceId, + }; + await this.prismaRepository.messageUpdate.create({ + data: messageUpdate, + }); } else { await this.prismaRepository.message.deleteMany({ where: { From 91e7a322099aa78ccbdbea15e0ea54e8dece48fd Mon Sep 17 00:00:00 2001 From: Aditya Nandwana Date: Mon, 3 Feb 2025 14:24:27 +0530 Subject: [PATCH 12/27] Refactor createJid method in BaileysStartupService --- .../integrations/channel/whatsapp/whatsapp.baileys.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index c53e2d4ce..519b5c88a 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -3900,7 +3900,7 @@ export class BaileysStartupService extends ChannelStartupService { } public async updateMessage(data: UpdateMessageDto) { - const jid = this.createJid(data.number); + const jid = createJid(data.number); const options = await this.formatUpdateMessage(data); From da74611769cb4a036324e56b625e4a5ce0ebccb0 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Mon, 3 Feb 2025 11:52:37 -0300 Subject: [PATCH 13/27] version: 2.2.3 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53119159f..2d3160418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 2.2.3 (develop) +# 2.2.3 (2025-02-03 11:52) ### Fixed From 867e8493aaeb702a1c5876a1e242e32d84dfb23a Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Mon, 3 Feb 2025 15:37:11 -0300 Subject: [PATCH 14/27] fix: added cache to identify duplicated messages on events - Update Docker image repository to evoapicloud/evolution-api - Modify contact email to contato@evolution-api.com - Update Docker Compose, Dockerfile, and workflow files - Add Docker image badge to README - Include additional content creator in README - Implement message deduplication cache in Baileys service --- .github/workflows/publish_docker_image.yml | 2 +- .../publish_docker_image_homolog.yml | 2 +- .../workflows/publish_docker_image_latest.yml | 2 +- Docker/swarm/evolution_api_v2.yaml | 2 +- Dockerfile | 2 +- LICENSE | 2 +- README.md | 4 +++- docker-compose.yaml | 2 +- package.json | 2 +- .../whatsapp/whatsapp.baileys.service.ts | 22 +++++++++++++++++++ 10 files changed, 33 insertions(+), 9 deletions(-) diff --git a/.github/workflows/publish_docker_image.yml b/.github/workflows/publish_docker_image.yml index 68a08a313..09d09390e 100644 --- a/.github/workflows/publish_docker_image.yml +++ b/.github/workflows/publish_docker_image.yml @@ -20,7 +20,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: atendai/evolution-api + images: evoapicloud/evolution-api tags: type=semver,pattern=v{{version}} - name: Set up QEMU diff --git a/.github/workflows/publish_docker_image_homolog.yml b/.github/workflows/publish_docker_image_homolog.yml index 77032dc95..b97a5e250 100644 --- a/.github/workflows/publish_docker_image_homolog.yml +++ b/.github/workflows/publish_docker_image_homolog.yml @@ -20,7 +20,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: atendai/evolution-api + images: evoapicloud/evolution-api tags: homolog - name: Set up QEMU diff --git a/.github/workflows/publish_docker_image_latest.yml b/.github/workflows/publish_docker_image_latest.yml index 641dc5e01..cffdab01e 100644 --- a/.github/workflows/publish_docker_image_latest.yml +++ b/.github/workflows/publish_docker_image_latest.yml @@ -20,7 +20,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: atendai/evolution-api + images: evoapicloud/evolution-api tags: latest - name: Set up QEMU diff --git a/Docker/swarm/evolution_api_v2.yaml b/Docker/swarm/evolution_api_v2.yaml index 41c2daa28..867251a53 100644 --- a/Docker/swarm/evolution_api_v2.yaml +++ b/Docker/swarm/evolution_api_v2.yaml @@ -2,7 +2,7 @@ version: "3.7" services: evolution_v2: - image: atendai/evolution-api:v2.1.2 + image: evoapicloud/evolution-api:latest volumes: - evolution_instances:/evolution/instances networks: diff --git a/Dockerfile b/Dockerfile index ca61b39a8..38cb416ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ RUN apk update && \ LABEL version="2.2.3" description="Api to control whatsapp features through http requests." LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" -LABEL contact="contato@atendai.com" +LABEL contact="contato@evolution-api.com" WORKDIR /evolution diff --git a/LICENSE b/LICENSE index da01e779d..ad430f14a 100644 --- a/LICENSE +++ b/LICENSE @@ -8,7 +8,7 @@ a. LOGO and copyright information: In the process of using Evolution API's front b. Usage Notification Requirement: If Evolution API is used as part of any project, including closed-source systems (e.g., proprietary software), the user is required to display a clear notification within the system that Evolution API is being utilized. This notification should be visible to system administrators and accessible from the system's documentation or settings page. Failure to comply with this requirement may result in the necessity for a commercial license, as determined by the producer. -Please contact contato@atendai.com to inquire about licensing matters. +Please contact contato@evolution-api.com to inquire about licensing matters. 2. As a contributor, you should agree that: diff --git a/README.md b/README.md index 93197499b..6e40ce741 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@
+[![Docker Image (https://img.shields.io/badge/Docker-Image-blue)](https://hub.docker.com/r/evoapicloud/evolution-api)] [![Whatsapp Group](https://img.shields.io/badge/Group-WhatsApp-%2322BC18)](https://evolution-api.com/whatsapp) [![Discord Community](https://img.shields.io/badge/Discord-Community-blue)](https://evolution-api.com/discord) [![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman) @@ -87,6 +88,7 @@ https://github.com/sponsors/EvolutionAPI We are proud to collaborate with the following content creators who have contributed valuable insights and tutorials about Evolution API: - [Promovaweb](https://www.youtube.com/@promovaweb) +- [Sandeco](https://www.youtube.com/@canalsandeco) - [Comunidade ZDG](https://www.youtube.com/@ComunidadeZDG) - [Francis MNO](https://www.youtube.com/@FrancisMNO) - [Pablo Cabral](https://youtube.com/@pablocabral) @@ -111,7 +113,7 @@ Evolution API is licensed under the Apache License 2.0, with the following addit 2. **Usage Notification Requirement**: If Evolution API is used as part of any project, including closed-source systems (e.g., proprietary software), the user is required to display a clear notification within the system that Evolution API is being utilized. This notification should be visible to system administrators and accessible from the system's documentation or settings page. Failure to comply with this requirement may result in the necessity for a commercial license, as determined by the producer. -Please contact contato@atendai.com to inquire about licensing matters. +Please contact contato@evolution-api.com to inquire about licensing matters. Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0). diff --git a/docker-compose.yaml b/docker-compose.yaml index 9a60a9a90..33918c383 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,7 +1,7 @@ services: api: container_name: evolution_api - image: atendai/evolution-api:homolog + image: evoapicloud/evolution-api:latest restart: always depends_on: - redis diff --git a/package.json b/package.json index 7e948028a..974f2a922 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ ], "author": { "name": "Davidson Gomes", - "email": "contato@atendai.com" + "email": "contato@evolution-api.com" }, "license": "Apache-2.0", "bugs": { diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 10feb7ce1..5f006a2c5 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -1161,6 +1161,17 @@ export class BaileysStartupService extends ChannelStartupService { await this.baileysCache.delete(received.key.id); } + // Cache to avoid duplicate messages + const messageKey = `${this.instance.id}_${received.key.id}`; + const cached = await this.baileysCache.get(messageKey); + + if (cached) { + this.logger.info(`Message duplicated ignored: ${received.key.id}`); + continue; + } + + await this.baileysCache.set(messageKey, true, 30 * 60); + if ( (type !== 'notify' && type !== 'append') || received.message?.protocolMessage || @@ -1422,6 +1433,17 @@ export class BaileysStartupService extends ChannelStartupService { continue; } + const updateKey = `${this.instance.id}_${key.id}_${update.status}`; + + const cached = await this.baileysCache.get(updateKey); + + if (cached) { + this.logger.info(`Message duplicated ignored: ${key.id}`); + continue; + } + + await this.baileysCache.set(updateKey, true, 30 * 60); + if (status[update.status] === 'READ' && key.fromMe) { if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) { this.chatwootService.eventWhatsapp( From e51b6e9270bc76a77f9bd283cb9f5926eb9ff060 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Mon, 3 Feb 2025 17:19:07 -0300 Subject: [PATCH 15/27] fix: improve message deduplication and edited message handling in Baileys service - Refactor edited message detection logic - Prevent duplicate message processing for edited messages - Optimize message key caching mechanism --- .gitignore | 2 ++ .../channel/whatsapp/whatsapp.baileys.service.ts | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a8226ede1..1cecfa988 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ /dist /node_modules +.cursor* + /Docker/.env .vscode diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 5f006a2c5..9f716545f 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -1128,9 +1128,10 @@ export class BaileysStartupService extends ChannelStartupService { } } + const editedMessage = + received?.message?.protocolMessage || received?.message?.editedMessage?.message?.protocolMessage; + if (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) { - const editedMessage = - received.message?.protocolMessage || received.message?.editedMessage?.message?.protocolMessage; if (editedMessage) { if (this.configService.get('CHATWOOT').ENABLED && this.localChatwoot?.enabled) this.chatwootService.eventWhatsapp( @@ -1165,7 +1166,7 @@ export class BaileysStartupService extends ChannelStartupService { const messageKey = `${this.instance.id}_${received.key.id}`; const cached = await this.baileysCache.get(messageKey); - if (cached) { + if (cached && !editedMessage) { this.logger.info(`Message duplicated ignored: ${received.key.id}`); continue; } From e27db0612fb9ed55253d5220b200afa062328ce3 Mon Sep 17 00:00:00 2001 From: Wayre Avelar Date: Tue, 4 Feb 2025 03:51:47 -0300 Subject: [PATCH 16/27] feat: Add support to get Catalogs and Collections with new routes: '{{baseUrl}}/chat/fetchCatalogs' and '{{baseUrl}}/chat/fetchCollections' --- src/api/controllers/chat.controller.ts | 10 ++ src/api/dto/chat.dto.ts | 11 ++ .../whatsapp/whatsapp.baileys.service.ts | 119 ++++++++++++++++++ src/api/routes/chat.router.ts | 24 ++++ src/validate/chat.schema.ts | 18 +++ 5 files changed, 182 insertions(+) diff --git a/src/api/controllers/chat.controller.ts b/src/api/controllers/chat.controller.ts index 207d8ba59..e814b8a83 100644 --- a/src/api/controllers/chat.controller.ts +++ b/src/api/controllers/chat.controller.ts @@ -13,6 +13,8 @@ import { SendPresenceDto, UpdateMessageDto, WhatsAppNumberDto, + getCatalogDto, + getCollectionsDto, } from '@api/dto/chat.dto'; import { InstanceDto } from '@api/dto/instance.dto'; import { Query } from '@api/repository/repository.service'; @@ -109,4 +111,12 @@ export class ChatController { public async blockUser({ instanceName }: InstanceDto, data: BlockUserDto) { return await this.waMonitor.waInstances[instanceName].blockUser(data); } + + public async fetchCatalog({ instanceName }: InstanceDto, data: getCatalogDto) { + return await this.waMonitor.waInstances[instanceName].fetchCatalog(instanceName, data); + } + + public async fetchCatalogCollections({ instanceName }: InstanceDto, data: getCollectionsDto) { + return await this.waMonitor.waInstances[instanceName].fetchCatalogCollections(instanceName, data); + } } diff --git a/src/api/dto/chat.dto.ts b/src/api/dto/chat.dto.ts index 00da7fdd4..1693165ee 100644 --- a/src/api/dto/chat.dto.ts +++ b/src/api/dto/chat.dto.ts @@ -126,3 +126,14 @@ export class BlockUserDto { number: string; status: 'block' | 'unblock'; } + +export class getCatalogDto { + number?: string; + limit?: number; + cursor?: string; +} + +export class getCollectionsDto { + number?: string; + limit?: number; +} diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 10feb7ce1..9bb04394b 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -13,6 +13,8 @@ import { SendPresenceDto, UpdateMessageDto, WhatsAppNumberDto, + getCatalogDto, + getCollectionsDto, } from '@api/dto/chat.dto'; import { AcceptGroupInvite, @@ -121,6 +123,9 @@ import makeWASocket, { WAMessageUpdate, WAPresence, WASocket, + Product, + GetCatalogOptions, + CatalogCollection, } from 'baileys'; import { Label } from 'baileys/lib/Types/Label'; import { LabelAssociation } from 'baileys/lib/Types/LabelAssociation'; @@ -4534,4 +4539,118 @@ export class BaileysStartupService extends ChannelStartupService { return response; } + + //Catalogs and collections + public async fetchCatalog(instanceName: string, data: getCatalogDto) { + const jid = data.number ? createJid(data.number) : this.client?.user?.id; + const limit = data.limit || 10; + const cursor = data.cursor || null; + + const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + + if (!onWhatsapp.exists) { + throw new BadRequestException(onWhatsapp); + } + + try { + const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + const business = await this.fetchBusinessProfile(info?.jid); + const catalog = await this.getCatalog({ jid: info?.jid, limit, cursor }); + + return { + wuid: info?.jid || jid, + name: info?.name, + numberExists: info?.exists, + isBusiness: business.isBusiness, + catalogLength: catalog?.products.length, + catalog: catalog?.products, + }; + } catch (error) { + console.log(error); + return { + wuid: jid, + name: null, + isBusiness: false, + }; + } + } + + public async getCatalog({ + jid, + limit, + cursor, + }: GetCatalogOptions): Promise<{ products: Product[]; nextPageCursor: string | undefined }> { + try { + jid = jid ? createJid(jid) : this.instance.wuid; + + const catalog = await this.client.getCatalog({ jid, limit: limit, cursor: cursor }); + + if (!catalog) { + return { + products: undefined, + nextPageCursor: undefined, + }; + } + + return catalog; + } catch (error) { + throw new InternalServerErrorException('Error getCatalog', error.toString()); + } + } + + public async fetchCatalogCollections(instanceName: string, data: getCollectionsDto) { + const jid = data.number ? createJid(data.number) : this.client?.user?.id; + const limit = data.limit || 10; + + const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + + if (!onWhatsapp.exists) { + throw new BadRequestException(onWhatsapp); + } + + try { + const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); + const business = await this.fetchBusinessProfile(info?.jid); + const catalogCollections = await this.getCollections(info?.jid, limit); + + return { + wuid: info?.jid || jid, + name: info?.name, + numberExists: info?.exists, + isBusiness: business.isBusiness, + catalogLength: catalogCollections?.length, + catalogCollections: catalogCollections, + }; + } catch (error) { + console.log(error); + return { + wuid: jid, + name: null, + isBusiness: false, + }; + } + } + + public async getCollections(jid?: string | undefined, limit?: number): Promise { + try { + jid = jid ? createJid(jid) : this.instance.wuid; + + const result = await this.client.getCollections(jid, limit); + + if (!result) { + return [ + { + id: undefined, + name: undefined, + products: [], + status: undefined, + }, + ]; + } + + return result.collections; + } catch (error) { + throw new InternalServerErrorException('Error getCatalog', error.toString()); + } + } } diff --git a/src/api/routes/chat.router.ts b/src/api/routes/chat.router.ts index 20126c1a5..715eba732 100644 --- a/src/api/routes/chat.router.ts +++ b/src/api/routes/chat.router.ts @@ -36,6 +36,8 @@ import { readMessageSchema, updateMessageSchema, whatsappNumberSchema, + catalogSchema, + collectionsSchema, } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; @@ -267,6 +269,28 @@ export class ChatRouter extends RouterBroker { }); return res.status(HttpStatus.CREATED).json(response); + }) + + .post(this.routerPath('fetchCatalog'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: catalogSchema, + ClassRef: NumberDto, + execute: (instance, data) => chatController.fetchCatalog(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + + .post(this.routerPath('fetchCollections'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: collectionsSchema, + ClassRef: NumberDto, + execute: (instance, data) => chatController.fetchCatalogCollections(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); }); } diff --git a/src/validate/chat.schema.ts b/src/validate/chat.schema.ts index dba279959..fd324c103 100644 --- a/src/validate/chat.schema.ts +++ b/src/validate/chat.schema.ts @@ -315,3 +315,21 @@ export const profileSchema: JSONSchema7 = { isBusiness: { type: 'boolean' }, }, }; + +export const catalogSchema: JSONSchema7 = { + type: 'object', + properties: { + number: { type: 'string' }, + limit: { type: 'number' }, + cursor: { type: 'string' }, + }, +}; + +export const collectionsSchema: JSONSchema7 = { + type: 'object', + properties: { + number: { type: 'string' }, + limit: { type: 'number' }, + cursor: { type: 'string' }, + }, +}; From 56a8e09ba868917321b9dcfe555aef979db9e6c9 Mon Sep 17 00:00:00 2001 From: Wayre Avelar Date: Tue, 4 Feb 2025 09:04:41 -0300 Subject: [PATCH 17/27] chore: eslint applied --- src/api/controllers/chat.controller.ts | 4 ++-- .../channel/whatsapp/whatsapp.baileys.service.ts | 10 +++++----- src/api/routes/chat.router.ts | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/api/controllers/chat.controller.ts b/src/api/controllers/chat.controller.ts index e814b8a83..8c922f11f 100644 --- a/src/api/controllers/chat.controller.ts +++ b/src/api/controllers/chat.controller.ts @@ -3,6 +3,8 @@ import { BlockUserDto, DeleteMessage, getBase64FromMediaMessageDto, + getCatalogDto, + getCollectionsDto, MarkChatUnreadDto, NumberDto, PrivacySettingDto, @@ -13,8 +15,6 @@ import { SendPresenceDto, UpdateMessageDto, WhatsAppNumberDto, - getCatalogDto, - getCollectionsDto, } from '@api/dto/chat.dto'; import { InstanceDto } from '@api/dto/instance.dto'; import { Query } from '@api/repository/repository.service'; diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 9bb04394b..bd0628f92 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -4,6 +4,8 @@ import { BlockUserDto, DeleteMessage, getBase64FromMediaMessageDto, + getCatalogDto, + getCollectionsDto, LastMessage, MarkChatUnreadDto, NumberBusiness, @@ -13,8 +15,6 @@ import { SendPresenceDto, UpdateMessageDto, WhatsAppNumberDto, - getCatalogDto, - getCollectionsDto, } from '@api/dto/chat.dto'; import { AcceptGroupInvite, @@ -93,6 +93,7 @@ import makeWASocket, { BufferedEventData, BufferJSON, CacheStore, + CatalogCollection, Chat, ConnectionState, Contact, @@ -102,6 +103,7 @@ import makeWASocket, { fetchLatestBaileysVersion, generateWAMessageFromContent, getAggregateVotesInPollMessage, + GetCatalogOptions, getContentType, getDevice, GroupMetadata, @@ -115,6 +117,7 @@ import makeWASocket, { MiscMessageGenerationOptions, ParticipantAction, prepareWAMessageMedia, + Product, proto, UserFacingSocketConfig, WABrowserDescription, @@ -123,9 +126,6 @@ import makeWASocket, { WAMessageUpdate, WAPresence, WASocket, - Product, - GetCatalogOptions, - CatalogCollection, } from 'baileys'; import { Label } from 'baileys/lib/Types/Label'; import { LabelAssociation } from 'baileys/lib/Types/LabelAssociation'; diff --git a/src/api/routes/chat.router.ts b/src/api/routes/chat.router.ts index 715eba732..aac9fe39c 100644 --- a/src/api/routes/chat.router.ts +++ b/src/api/routes/chat.router.ts @@ -22,6 +22,8 @@ import { Contact, Message, MessageUpdate } from '@prisma/client'; import { archiveChatSchema, blockUserSchema, + catalogSchema, + collectionsSchema, contactValidateSchema, deleteMessageSchema, markChatUnreadSchema, @@ -36,8 +38,6 @@ import { readMessageSchema, updateMessageSchema, whatsappNumberSchema, - catalogSchema, - collectionsSchema, } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; From 9a72b90ab2b34b8df10bb0e103acf55ce04f0011 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Tue, 4 Feb 2025 17:57:21 -0300 Subject: [PATCH 18/27] refactor: Make RabbitMQ prefix key optional in configuration --- src/config/env.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/env.config.ts b/src/config/env.config.ts index 78ca891cd..8ba1fa833 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -97,7 +97,7 @@ export type Rabbitmq = { EXCHANGE_NAME: string; GLOBAL_ENABLED: boolean; EVENTS: EventsRabbitmq; - PREFIX_KEY: string; + PREFIX_KEY?: string; }; export type Sqs = { @@ -356,7 +356,7 @@ export class ConfigService { RABBITMQ: { ENABLED: process.env?.RABBITMQ_ENABLED === 'true', GLOBAL_ENABLED: process.env?.RABBITMQ_GLOBAL_ENABLED === 'true', - PREFIX_KEY: process.env?.RABBITMQ_PREFIX_KEY || 'evolution', + PREFIX_KEY: process.env?.RABBITMQ_PREFIX_KEY, EXCHANGE_NAME: process.env?.RABBITMQ_EXCHANGE_NAME || 'evolution_exchange', URI: process.env.RABBITMQ_URI || '', EVENTS: { From 0d1e7c08c9568fa590211bafe2649195228e83c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Souza?= Date: Thu, 6 Feb 2025 17:56:21 -0300 Subject: [PATCH 19/27] feat: sendsticket notconvertsticket --- src/api/dto/sendMessage.dto.ts | 1 + .../integrations/channel/whatsapp/whatsapp.baileys.service.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/dto/sendMessage.dto.ts b/src/api/dto/sendMessage.dto.ts index 1c9b11545..ba9ecf527 100644 --- a/src/api/dto/sendMessage.dto.ts +++ b/src/api/dto/sendMessage.dto.ts @@ -44,6 +44,7 @@ export class Metadata { mentionsEveryOne?: boolean; mentioned?: string[]; encoding?: boolean; + notConvertSticker?: boolean; } export class SendTextDto extends Metadata { diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 0afd5318a..78993547e 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -2660,7 +2660,9 @@ export class BaileysStartupService extends ChannelStartupService { if (file) mediaData.sticker = file.buffer.toString('base64'); - const convert = await this.convertToWebP(data.sticker); + const convert = data?.notConvertSticker + ? Buffer.from(data.sticker, 'base64') + : await this.convertToWebP(data.sticker); const gifPlayback = data.sticker.includes('.gif'); const result = await this.sendMessageWithTyping( data.number, From 95401cf9b03ac19cb6fe2b18a9d33b0c01bb75b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Souza?= <47183663+joaosouz4dev@users.noreply.github.com> Date: Thu, 6 Feb 2025 18:05:31 -0300 Subject: [PATCH 20/27] fix: rollback deploy_database.sh --- Docker/scripts/deploy_database.sh | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/Docker/scripts/deploy_database.sh b/Docker/scripts/deploy_database.sh index 4ee735ee7..fde46d120 100755 --- a/Docker/scripts/deploy_database.sh +++ b/Docker/scripts/deploy_database.sh @@ -1,36 +1,24 @@ #!/bin/bash -# Fonte das variáveis de ambiente source ./Docker/scripts/env_functions.sh -# Carregar variáveis de ambiente se não estiver no ambiente Docker if [ "$DOCKER_ENV" != "true" ]; then export_env_vars fi -# Verificar se o banco de dados é PostgreSQL ou MySQL if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]]; then export DATABASE_URL echo "Deploying migrations for $DATABASE_PROVIDER" echo "Database URL: $DATABASE_URL" - - # Verificar se há migrações pendentes com Prisma - MIGRATION_STATUS=$(npx prisma migrate status) - - if echo "$MIGRATION_STATUS" | grep -q "Pending"; then - echo "Migrações pendentes encontradas. Executando deploy..." - npm run db:deploy # Aplica as migrações pendentes - if [ $? -ne 0 ]; then - echo "Migration failed" - exit 1 - else - echo "Migration succeeded" - fi + # rm -rf ./prisma/migrations + # cp -r ./prisma/$DATABASE_PROVIDER-migrations ./prisma/migrations + npm run db:deploy + if [ $? -ne 0 ]; then + echo "Migration failed" + exit 1 else - echo "Nenhuma migração pendente. Pulando deploy." + echo "Migration succeeded" fi - - # Gerar o Prisma Client após o deploy npm run db:generate if [ $? -ne 0 ]; then echo "Prisma generate failed" @@ -38,7 +26,6 @@ if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]] else echo "Prisma generate succeeded" fi - else echo "Error: Database provider $DATABASE_PROVIDER invalid." exit 1 From 6c1355b64b47a6f382bf558799e75c626cc33a65 Mon Sep 17 00:00:00 2001 From: Wayre Avelar Date: Thu, 6 Feb 2025 19:04:28 -0300 Subject: [PATCH 21/27] =?UTF-8?q?feat:=20Criado=20um=20novo=20grupo=20de?= =?UTF-8?q?=20rotas=20(business)=20para=20tratar=20dos=20catalogos=20de=20?= =?UTF-8?q?produtos=20e=20Cole=C3=A7=C3=B5es=20evitando=20altera=C3=A7?= =?UTF-8?q?=C3=B5es=20desnecess=C3=A1rias=20em=20arquivos=20do=20reposit?= =?UTF-8?q?=C3=B3rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/controllers/business.controller.ts | 15 ++++++ src/api/controllers/chat.controller.ts | 10 ---- src/api/dto/business.dto.ts | 14 ++++++ src/api/dto/chat.dto.ts | 11 ----- .../whatsapp/whatsapp.baileys.service.ts | 48 +++++++++++++------ src/api/routes/business.router.ts | 37 ++++++++++++++ src/api/routes/chat.router.ts | 25 ---------- src/api/routes/index.router.ts | 2 + src/api/server.module.ts | 2 + src/validate/business.schema.ts | 17 +++++++ src/validate/chat.schema.ts | 18 ------- src/validate/validate.schema.ts | 1 + 12 files changed, 121 insertions(+), 79 deletions(-) create mode 100644 src/api/controllers/business.controller.ts create mode 100644 src/api/dto/business.dto.ts create mode 100644 src/api/routes/business.router.ts create mode 100644 src/validate/business.schema.ts diff --git a/src/api/controllers/business.controller.ts b/src/api/controllers/business.controller.ts new file mode 100644 index 000000000..3c7f166cc --- /dev/null +++ b/src/api/controllers/business.controller.ts @@ -0,0 +1,15 @@ +import { getCatalogDto, getCollectionsDto } from '@api/dto/business.dto'; +import { InstanceDto } from '@api/dto/instance.dto'; +import { WAMonitoringService } from '@api/services/monitor.service'; + +export class BusinessController { + constructor(private readonly waMonitor: WAMonitoringService) {} + + public async fetchCatalog({ instanceName }: InstanceDto, data: getCatalogDto) { + return await this.waMonitor.waInstances[instanceName].fetchCatalog(instanceName, data); + } + + public async fetchCollections({ instanceName }: InstanceDto, data: getCollectionsDto) { + return await this.waMonitor.waInstances[instanceName].fetchCollections(instanceName, data); + } +} diff --git a/src/api/controllers/chat.controller.ts b/src/api/controllers/chat.controller.ts index 8c922f11f..207d8ba59 100644 --- a/src/api/controllers/chat.controller.ts +++ b/src/api/controllers/chat.controller.ts @@ -3,8 +3,6 @@ import { BlockUserDto, DeleteMessage, getBase64FromMediaMessageDto, - getCatalogDto, - getCollectionsDto, MarkChatUnreadDto, NumberDto, PrivacySettingDto, @@ -111,12 +109,4 @@ export class ChatController { public async blockUser({ instanceName }: InstanceDto, data: BlockUserDto) { return await this.waMonitor.waInstances[instanceName].blockUser(data); } - - public async fetchCatalog({ instanceName }: InstanceDto, data: getCatalogDto) { - return await this.waMonitor.waInstances[instanceName].fetchCatalog(instanceName, data); - } - - public async fetchCatalogCollections({ instanceName }: InstanceDto, data: getCollectionsDto) { - return await this.waMonitor.waInstances[instanceName].fetchCatalogCollections(instanceName, data); - } } diff --git a/src/api/dto/business.dto.ts b/src/api/dto/business.dto.ts new file mode 100644 index 000000000..d29b3cf97 --- /dev/null +++ b/src/api/dto/business.dto.ts @@ -0,0 +1,14 @@ +export class NumberDto { + number: string; +} + +export class getCatalogDto { + number?: string; + limit?: number; + cursor?: string; +} + +export class getCollectionsDto { + number?: string; + limit?: number; +} diff --git a/src/api/dto/chat.dto.ts b/src/api/dto/chat.dto.ts index 1693165ee..00da7fdd4 100644 --- a/src/api/dto/chat.dto.ts +++ b/src/api/dto/chat.dto.ts @@ -126,14 +126,3 @@ export class BlockUserDto { number: string; status: 'block' | 'unblock'; } - -export class getCatalogDto { - number?: string; - limit?: number; - cursor?: string; -} - -export class getCollectionsDto { - number?: string; - limit?: number; -} diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 57197e176..d1a4f2e64 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -1,11 +1,10 @@ +import { getCollectionsDto } from '@api/dto/business.dto'; import { OfferCallDto } from '@api/dto/call.dto'; import { ArchiveChatDto, BlockUserDto, DeleteMessage, getBase64FromMediaMessageDto, - getCatalogDto, - getCollectionsDto, LastMessage, MarkChatUnreadDto, NumberBusiness, @@ -4634,11 +4633,11 @@ export class BaileysStartupService extends ChannelStartupService { return response; } - //Catalogs and collections - public async fetchCatalog(instanceName: string, data: getCatalogDto) { + //Business Controller + public async fetchCatalog(instanceName: string, data: getCollectionsDto) { const jid = data.number ? createJid(data.number) : this.client?.user?.id; const limit = data.limit || 10; - const cursor = data.cursor || null; + const cursor = null; const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); @@ -4649,15 +4648,35 @@ export class BaileysStartupService extends ChannelStartupService { try { const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); const business = await this.fetchBusinessProfile(info?.jid); - const catalog = await this.getCatalog({ jid: info?.jid, limit, cursor }); + + let catalog = await this.getCatalog({ jid: info?.jid, limit, cursor }); + let nextPageCursor = catalog.nextPageCursor; + let nextPageCursorJson = nextPageCursor ? JSON.parse(atob(nextPageCursor)) : null; + let pagination = nextPageCursorJson?.pagination_cursor + ? JSON.parse(atob(nextPageCursorJson.pagination_cursor)) + : null; + let fetcherHasMore = pagination?.fetcher_has_more === true ? true : false; + + let productsCatalog = catalog.products || []; + let countLoops = 0; + while (fetcherHasMore && countLoops < 4) { + catalog = await this.getCatalog({ jid: info?.jid, limit, cursor: nextPageCursor }); + nextPageCursor = catalog.nextPageCursor; + nextPageCursorJson = nextPageCursor ? JSON.parse(atob(nextPageCursor)) : null; + pagination = nextPageCursorJson?.pagination_cursor + ? JSON.parse(atob(nextPageCursorJson.pagination_cursor)) + : null; + fetcherHasMore = pagination?.fetcher_has_more === true ? true : false; + productsCatalog = [...productsCatalog, ...catalog.products]; + countLoops++; + } return { wuid: info?.jid || jid, - name: info?.name, numberExists: info?.exists, isBusiness: business.isBusiness, - catalogLength: catalog?.products.length, - catalog: catalog?.products, + catalogLength: productsCatalog.length, + catalog: productsCatalog, }; } catch (error) { console.log(error); @@ -4692,9 +4711,9 @@ export class BaileysStartupService extends ChannelStartupService { } } - public async fetchCatalogCollections(instanceName: string, data: getCollectionsDto) { + public async fetchCollections(instanceName: string, data: getCollectionsDto) { const jid = data.number ? createJid(data.number) : this.client?.user?.id; - const limit = data.limit || 10; + const limit = data.limit <= 20 ? data.limit : 20; //(tem esse limite, não sei porque) const onWhatsapp = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); @@ -4705,18 +4724,17 @@ export class BaileysStartupService extends ChannelStartupService { try { const info = (await this.whatsappNumber({ numbers: [jid] }))?.shift(); const business = await this.fetchBusinessProfile(info?.jid); - const catalogCollections = await this.getCollections(info?.jid, limit); + const collections = await this.getCollections(info?.jid, limit); return { wuid: info?.jid || jid, name: info?.name, numberExists: info?.exists, isBusiness: business.isBusiness, - catalogLength: catalogCollections?.length, - catalogCollections: catalogCollections, + collectionsLength: collections?.length, + collections: collections, }; } catch (error) { - console.log(error); return { wuid: jid, name: null, diff --git a/src/api/routes/business.router.ts b/src/api/routes/business.router.ts new file mode 100644 index 000000000..1e510a4ff --- /dev/null +++ b/src/api/routes/business.router.ts @@ -0,0 +1,37 @@ +import { RouterBroker } from '@api/abstract/abstract.router'; +import { NumberDto } from '@api/dto/chat.dto'; +import { businessController } from '@api/server.module'; +import { catalogSchema, collectionsSchema } from '@validate/validate.schema'; +import { RequestHandler, Router } from 'express'; + +import { HttpStatus } from './index.router'; + +export class BusinessRouter extends RouterBroker { + constructor(...guards: RequestHandler[]) { + super(); + this.router + .post(this.routerPath('getCatalog'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: catalogSchema, + ClassRef: NumberDto, + execute: (instance, data) => businessController.fetchCatalog(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }) + + .post(this.routerPath('getCollections'), ...guards, async (req, res) => { + const response = await this.dataValidate({ + request: req, + schema: collectionsSchema, + ClassRef: NumberDto, + execute: (instance, data) => businessController.fetchCollections(instance, data), + }); + + return res.status(HttpStatus.OK).json(response); + }); + } + + public readonly router: Router = Router(); +} diff --git a/src/api/routes/chat.router.ts b/src/api/routes/chat.router.ts index aac9fe39c..5c556705e 100644 --- a/src/api/routes/chat.router.ts +++ b/src/api/routes/chat.router.ts @@ -22,8 +22,6 @@ import { Contact, Message, MessageUpdate } from '@prisma/client'; import { archiveChatSchema, blockUserSchema, - catalogSchema, - collectionsSchema, contactValidateSchema, deleteMessageSchema, markChatUnreadSchema, @@ -209,7 +207,6 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) - .post(this.routerPath('updateProfileName'), ...guards, async (req, res) => { const response = await this.dataValidate({ request: req, @@ -269,28 +266,6 @@ export class ChatRouter extends RouterBroker { }); return res.status(HttpStatus.CREATED).json(response); - }) - - .post(this.routerPath('fetchCatalog'), ...guards, async (req, res) => { - const response = await this.dataValidate({ - request: req, - schema: catalogSchema, - ClassRef: NumberDto, - execute: (instance, data) => chatController.fetchCatalog(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); - }) - - .post(this.routerPath('fetchCollections'), ...guards, async (req, res) => { - const response = await this.dataValidate({ - request: req, - schema: collectionsSchema, - ClassRef: NumberDto, - execute: (instance, data) => chatController.fetchCatalogCollections(instance, data), - }); - - return res.status(HttpStatus.OK).json(response); }); } diff --git a/src/api/routes/index.router.ts b/src/api/routes/index.router.ts index a4a7c0717..9c0ecd13c 100644 --- a/src/api/routes/index.router.ts +++ b/src/api/routes/index.router.ts @@ -11,6 +11,7 @@ import fs from 'fs'; import mimeTypes from 'mime-types'; import path from 'path'; +import { BusinessRouter } from './business.router'; import { CallRouter } from './call.router'; import { ChatRouter } from './chat.router'; import { GroupRouter } from './group.router'; @@ -82,6 +83,7 @@ router .use('/message', new MessageRouter(...guards).router) .use('/call', new CallRouter(...guards).router) .use('/chat', new ChatRouter(...guards).router) + .use('/business', new BusinessRouter(...guards).router) .use('/group', new GroupRouter(...guards).router) .use('/template', new TemplateRouter(configService, ...guards).router) .use('/settings', new SettingsRouter(...guards).router) diff --git a/src/api/server.module.ts b/src/api/server.module.ts index 49fc56952..9d8df8a67 100644 --- a/src/api/server.module.ts +++ b/src/api/server.module.ts @@ -3,6 +3,7 @@ import { Chatwoot, configService, ProviderSession } from '@config/env.config'; import { eventEmitter } from '@config/event.config'; import { Logger } from '@config/logger.config'; +import { BusinessController } from './controllers/business.controller'; import { CallController } from './controllers/call.controller'; import { ChatController } from './controllers/chat.controller'; import { GroupController } from './controllers/group.controller'; @@ -98,6 +99,7 @@ export const instanceController = new InstanceController( export const sendMessageController = new SendMessageController(waMonitor); export const callController = new CallController(waMonitor); export const chatController = new ChatController(waMonitor); +export const businessController = new BusinessController(waMonitor); export const groupController = new GroupController(waMonitor); export const labelController = new LabelController(waMonitor); diff --git a/src/validate/business.schema.ts b/src/validate/business.schema.ts new file mode 100644 index 000000000..91ad17b20 --- /dev/null +++ b/src/validate/business.schema.ts @@ -0,0 +1,17 @@ +import { JSONSchema7 } from 'json-schema'; + +export const catalogSchema: JSONSchema7 = { + type: 'object', + properties: { + number: { type: 'string' }, + limit: { type: 'number' }, + }, +}; + +export const collectionsSchema: JSONSchema7 = { + type: 'object', + properties: { + number: { type: 'string' }, + limit: { type: 'number' }, + }, +}; diff --git a/src/validate/chat.schema.ts b/src/validate/chat.schema.ts index fd324c103..dba279959 100644 --- a/src/validate/chat.schema.ts +++ b/src/validate/chat.schema.ts @@ -315,21 +315,3 @@ export const profileSchema: JSONSchema7 = { isBusiness: { type: 'boolean' }, }, }; - -export const catalogSchema: JSONSchema7 = { - type: 'object', - properties: { - number: { type: 'string' }, - limit: { type: 'number' }, - cursor: { type: 'string' }, - }, -}; - -export const collectionsSchema: JSONSchema7 = { - type: 'object', - properties: { - number: { type: 'string' }, - limit: { type: 'number' }, - cursor: { type: 'string' }, - }, -}; diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index cf3d7828c..4577eae3f 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -1,4 +1,5 @@ // Integrations Schema +export * from './business.schema'; export * from './chat.schema'; export * from './group.schema'; export * from './instance.schema'; From 736ca5e4b605f1368bd40350ee1a122f2a6c4b10 Mon Sep 17 00:00:00 2001 From: Rafael Souza Date: Fri, 7 Feb 2025 09:52:08 -0300 Subject: [PATCH 22/27] Fix case in table name --- prisma/mysql-schema.prisma | 2 +- prisma/postgresql-schema.prisma | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma index a73ca0693..d93734e44 100644 --- a/prisma/mysql-schema.prisma +++ b/prisma/mysql-schema.prisma @@ -99,7 +99,7 @@ model Instance { Template Template[] Dify Dify[] DifySetting DifySetting? - integrationSessions IntegrationSession[] + IntegrationSessions IntegrationSession[] EvolutionBot EvolutionBot[] EvolutionBotSetting EvolutionBotSetting? Flowise Flowise[] diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index a9782ce5e..3c94b8080 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -99,7 +99,7 @@ model Instance { Template Template[] Dify Dify[] DifySetting DifySetting? - integrationSessions IntegrationSession[] + IntegrationSessions IntegrationSession[] EvolutionBot EvolutionBot[] EvolutionBotSetting EvolutionBotSetting? Flowise Flowise[] From 5a50381a8e34bff7c36b11c2bb803243ce63c92f Mon Sep 17 00:00:00 2001 From: Rafael Souza Date: Fri, 7 Feb 2025 10:07:38 -0300 Subject: [PATCH 23/27] Fix table name --- prisma/mysql-schema.prisma | 2 +- prisma/postgresql-schema.prisma | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/prisma/mysql-schema.prisma b/prisma/mysql-schema.prisma index d93734e44..f2dbb9412 100644 --- a/prisma/mysql-schema.prisma +++ b/prisma/mysql-schema.prisma @@ -99,7 +99,7 @@ model Instance { Template Template[] Dify Dify[] DifySetting DifySetting? - IntegrationSessions IntegrationSession[] + IntegrationSession IntegrationSession[] EvolutionBot EvolutionBot[] EvolutionBotSetting EvolutionBotSetting? Flowise Flowise[] diff --git a/prisma/postgresql-schema.prisma b/prisma/postgresql-schema.prisma index 3c94b8080..bea632f1c 100644 --- a/prisma/postgresql-schema.prisma +++ b/prisma/postgresql-schema.prisma @@ -99,7 +99,7 @@ model Instance { Template Template[] Dify Dify[] DifySetting DifySetting? - IntegrationSessions IntegrationSession[] + IntegrationSession IntegrationSession[] EvolutionBot EvolutionBot[] EvolutionBotSetting EvolutionBotSetting? Flowise Flowise[] From d75c37e233fb08f6b970d6872d55e3a5ff56953c Mon Sep 17 00:00:00 2001 From: Alexis Hernandez Date: Fri, 7 Feb 2025 13:04:36 -0400 Subject: [PATCH 24/27] feat: add message location support meta --- .../channel/meta/whatsapp.business.service.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/api/integrations/channel/meta/whatsapp.business.service.ts b/src/api/integrations/channel/meta/whatsapp.business.service.ts index 5360b9e49..c6f223a9c 100644 --- a/src/api/integrations/channel/meta/whatsapp.business.service.ts +++ b/src/api/integrations/channel/meta/whatsapp.business.service.ts @@ -206,6 +206,20 @@ export class BusinessStartupService extends ChannelStartupService { return content; } + private messageLocationJson(received: any) { + const message = received.messages[0]; + let content: any = { + locationMessage: { + degreesLatitude: message.location.latitude, + degreesLongitude: message.location.longitude, + name: message.location?.name, + address: message.location?.address, + }, + }; + message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content; + return content; + } + private messageContactsJson(received: any) { const message = received.messages[0]; let content: any = {}; @@ -283,6 +297,9 @@ export class BusinessStartupService extends ChannelStartupService { case 'template': messageType = 'conversation'; break; + case 'location': + messageType = 'locationMessage'; + break; default: messageType = 'conversation'; break; @@ -438,6 +455,17 @@ export class BusinessStartupService extends ChannelStartupService { source: 'unknown', instanceId: this.instanceId, }; + } else if (received?.messages[0].location) { + messageRaw = { + key, + pushName, + message: this.messageLocationJson(received), + contextInfo: this.messageLocationJson(received)?.contextInfo, + messageType: this.renderMessageType(received.messages[0].type), + messageTimestamp: parseInt(received.messages[0].timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, + }; } else { messageRaw = { key, From 1741a727a811ee93c0b30e02b10698f4bbbed6bc Mon Sep 17 00:00:00 2001 From: mbap-dev Date: Sun, 9 Feb 2025 20:12:40 -0300 Subject: [PATCH 25/27] Fix audio send duplicate from chatwoot. (cherry picked from commit 6b120e5da2704f267cb9ea17f7f0f00cfc361fe3) --- .../integrations/chatbot/chatwoot/services/chatwoot.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index 77b58bbe7..673e6ac5d 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -1106,7 +1106,7 @@ export class ChatwootService { sendTelemetry('/message/sendWhatsAppAudio'); - const messageSent = await waInstance?.audioWhatsapp(data, true); + const messageSent = await waInstance?.audioWhatsapp(data, null, true); return messageSent; } From cc904ccb04c5690915d605aab9b1e9ca63a2312e Mon Sep 17 00:00:00 2001 From: mbap-dev Date: Sun, 9 Feb 2025 20:16:41 -0300 Subject: [PATCH 26/27] fix build --- .github/workflows/publish_docker_image_homolog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_docker_image_homolog.yml b/.github/workflows/publish_docker_image_homolog.yml index b97a5e250..3dc4aaf16 100644 --- a/.github/workflows/publish_docker_image_homolog.yml +++ b/.github/workflows/publish_docker_image_homolog.yml @@ -20,7 +20,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: evoapicloud/evolution-api + images: mbppereira/evolution-api tags: homolog - name: Set up QEMU From 89477262f447ad166eb2124add1628961ac92f66 Mon Sep 17 00:00:00 2001 From: mbap-dev Date: Fri, 14 Mar 2025 14:02:35 -0300 Subject: [PATCH 27/27] update baileys to v6.7.16 --- package-lock.json | 247 +++++++++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 167 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83bd4d16c..350b72f5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@sentry/node": "^8.47.0", "amqplib": "^0.10.5", "axios": "^1.7.9", - "baileys": "github:EvolutionAPI/Baileys", + "baileys": "github:mbap-dev/Baileys#v6.7.16", "class-validator": "^0.14.1", "compression": "^1.7.5", "cors": "^2.8.5", @@ -701,6 +701,24 @@ "node": ">=6.9.0" } }, + "node_modules/@cacheable/node-cache": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@cacheable/node-cache/-/node-cache-1.5.3.tgz", + "integrity": "sha512-xJCYqoxkwg8vpQ/wSv0p4o+j/VEEnP7TUDUsV+VoPVVuwpsUKxU0wyz+VWBbq0SbX6e/oi/jiR/LDQ46miDQ8A==", + "dependencies": { + "cacheable": "^1.8.9", + "hookified": "^1.7.1", + "keyv": "^5.3.1" + } + }, + "node_modules/@cacheable/node-cache/node_modules/keyv": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.3.1.tgz", + "integrity": "sha512-13hQT2q2VIwOoaJdJa7nY3J8UVbYtMTJFHnwm9LI+SaQRfUiM6Em9KZeOVTCKbMnGcRIL3NSUFpAdjZCq24nLQ==", + "dependencies": { + "@keyv/serialize": "^1.0.3" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -1091,7 +1109,9 @@ "node_modules/@eshaz/web-worker": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@eshaz/web-worker/-/web-worker-1.2.2.tgz", - "integrity": "sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==" + "integrity": "sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==", + "optional": true, + "peer": true }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", @@ -1935,6 +1955,37 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@keyv/serialize": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.0.3.tgz", + "integrity": "sha512-qnEovoOp5Np2JDGonIDL6Ayihw0RhnRh6vxPuHo4RDn1UOzwEo4AeIfpL6UGIrsceWrCMiVPgwRjbHu4vYFc3g==", + "dependencies": { + "buffer": "^6.0.3" + } + }, + "node_modules/@keyv/serialize/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/@noble/hashes": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", @@ -3604,6 +3655,8 @@ "url": "https://liberapay.com/thi.ng" } ], + "optional": true, + "peer": true, "dependencies": { "@thi.ng/errors": "^2.5.25" }, @@ -3629,6 +3682,8 @@ "url": "https://liberapay.com/thi.ng" } ], + "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -4109,6 +4164,8 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/common/-/common-9.0.5.tgz", "integrity": "sha512-b9JNh9sPAvn8PVIizNh9D60WkfQong/u9ea873H47u7zvVDLctxYIp2aZw9CQqXaQdk7JB3MoU5UHiseO40swg==", + "optional": true, + "peer": true, "dependencies": { "@eshaz/web-worker": "1.2.2", "simple-yenc": "^1.0.4" @@ -4118,6 +4175,8 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/flac/-/flac-0.2.5.tgz", "integrity": "sha512-8M//CgB3PlkWwn47KcwD0tO6DZBA7/AGG0ukHSG0G97UbNEUNINvKDWAKPVWznzHsqeBP6axw+K/38dzng64JA==", + "optional": true, + "peer": true, "dependencies": { "@wasm-audio-decoders/common": "9.0.5", "codec-parser": "2.5.0" @@ -4131,6 +4190,8 @@ "version": "0.1.16", "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/ogg-vorbis/-/ogg-vorbis-0.1.16.tgz", "integrity": "sha512-HcEx4LPZbbzjhs9bTXgMaXLVCSMSo/egY9paJxAnE9tsYbvseAaGtVddLYktl3Qi/G+nW/ZzUXg4144izJjqCw==", + "optional": true, + "peer": true, "dependencies": { "@wasm-audio-decoders/common": "9.0.5", "codec-parser": "2.5.0" @@ -4681,6 +4742,14 @@ "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==" }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4697,12 +4766,16 @@ "node_modules/audio-buffer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/audio-buffer/-/audio-buffer-5.0.0.tgz", - "integrity": "sha512-gsDyj1wwUp8u7NBB+eW6yhLb9ICf+0eBmDX8NGaAS00w8/fLqFdxUlL5Ge/U8kB64DlQhdonxYC59dXy1J7H/w==" + "integrity": "sha512-gsDyj1wwUp8u7NBB+eW6yhLb9ICf+0eBmDX8NGaAS00w8/fLqFdxUlL5Ge/U8kB64DlQhdonxYC59dXy1J7H/w==", + "optional": true, + "peer": true }, "node_modules/audio-decode": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/audio-decode/-/audio-decode-2.2.2.tgz", "integrity": "sha512-xyh7z6dpRT+5Ez4ggV2cEkSShkDvvIBBmVPR3kYY7uIBqRO1BGNjofip6JnjBnvezhrU3ypBGZjepyKFDZWnDw==", + "optional": true, + "peer": true, "dependencies": { "@wasm-audio-decoders/flac": "^0.2.4", "@wasm-audio-decoders/ogg-vorbis": "^0.1.15", @@ -4718,6 +4791,8 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/audio-type/-/audio-type-2.2.1.tgz", "integrity": "sha512-En9AY6EG1qYqEy5L/quryzbA4akBpJrnBZNxeKTqGHC2xT9Qc4aZ8b7CcbOMFTTc/MGdoNyp+SN4zInZNKxMYA==", + "optional": true, + "peer": true, "engines": { "node": ">=14" } @@ -4752,41 +4827,43 @@ "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" }, "node_modules/baileys": { - "version": "6.7.12", - "resolved": "git+ssh://git@github.com/EvolutionAPI/Baileys.git#2c69f65d4b6c4e779d6e3d2c0c32689a5425df95", + "version": "6.7.16", + "resolved": "git+ssh://git@github.com/mbap-dev/Baileys.git#efcd93f582391b25795e6930dbb4293ff98b0dc7", + "hasInstallScript": true, "dependencies": { "@adiwajshing/keyed-db": "^0.2.4", + "@cacheable/node-cache": "^1.4.0", "@hapi/boom": "^9.1.3", "@whiskeysockets/eslint-config": "github:whiskeysockets/eslint-config", "async-lock": "^1.4.1", - "audio-decode": "^2.1.3", + "async-mutex": "^0.5.0", "axios": "^1.6.0", "cache-manager": "^5.7.6", - "futoin-hkdf": "^1.5.1", - "libphonenumber-js": "^1.10.20", "libsignal": "github:WhiskeySockets/libsignal-node", "lodash": "^4.17.21", "music-metadata": "^7.12.3", - "node-cache": "^5.1.2", - "pino": "^7.0.0", + "pino": "^9.6", "protobufjs": "^7.2.4", "uuid": "^10.0.0", "ws": "^8.13.0" }, + "engines": { + "node": ">=20.0.0" + }, "peerDependencies": { + "audio-decode": "^2.1.3", "jimp": "^0.16.1", "link-preview-js": "^3.0.0", - "qrcode-terminal": "^0.12.0", "sharp": "^0.32.6" }, "peerDependenciesMeta": { - "jimp": { + "audio-decode": { "optional": true }, - "link-preview-js": { + "jimp": { "optional": true }, - "qrcode-terminal": { + "link-preview-js": { "optional": true }, "sharp": { @@ -4807,73 +4884,69 @@ "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" }, - "node_modules/baileys/node_modules/on-exit-leak-free": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", - "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==" - }, "node_modules/baileys/node_modules/pino": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", - "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.6.0.tgz", + "integrity": "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==", "dependencies": { "atomic-sleep": "^1.0.0", - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^0.2.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^4.0.0", - "process-warning": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^2.2.1", - "thread-stream": "^0.15.1" + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "node_modules/baileys/node_modules/pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", "dependencies": { - "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "node_modules/baileys/node_modules/pino-std-serializers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", - "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==" }, "node_modules/baileys/node_modules/process-warning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", - "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" - }, - "node_modules/baileys/node_modules/real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", - "engines": { - "node": ">= 12.13.0" - } + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] }, "node_modules/baileys/node_modules/sonic-boom": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", - "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", "dependencies": { "atomic-sleep": "^1.0.0" } }, "node_modules/baileys/node_modules/thread-stream": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", - "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", "dependencies": { - "real-require": "^0.1.0" + "real-require": "^0.2.0" } }, "node_modules/baileys/node_modules/uuid": { @@ -5188,6 +5261,23 @@ "node": ">= 18" } }, + "node_modules/cacheable": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.8.9.tgz", + "integrity": "sha512-FicwAUyWnrtnd4QqYAoRlNs44/a1jTL7XDKqm5gJ90wz1DQPlC7U2Rd1Tydpv+E7WAr4sQHuw8Q8M3nZMAyecQ==", + "dependencies": { + "hookified": "^1.7.1", + "keyv": "^5.3.1" + } + }, + "node_modules/cacheable/node_modules/keyv": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.3.1.tgz", + "integrity": "sha512-13hQT2q2VIwOoaJdJa7nY3J8UVbYtMTJFHnwm9LI+SaQRfUiM6Em9KZeOVTCKbMnGcRIL3NSUFpAdjZCq24nLQ==", + "dependencies": { + "@keyv/serialize": "^1.0.3" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -5396,7 +5486,9 @@ "node_modules/codec-parser": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/codec-parser/-/codec-parser-2.5.0.tgz", - "integrity": "sha512-Ru9t80fV8B0ZiixQl8xhMTLru+dzuis/KQld32/x5T/+3LwZb0/YvQdSKytX9JqCnRdiupvAvyYJINKrXieziQ==" + "integrity": "sha512-Ru9t80fV8B0ZiixQl8xhMTLru+dzuis/KQld32/x5T/+3LwZb0/YvQdSKytX9JqCnRdiupvAvyYJINKrXieziQ==", + "optional": true, + "peer": true }, "node_modules/color": { "version": "4.2.3", @@ -5991,17 +6083,6 @@ "node": ">= 0.4" } }, - "node_modules/duplexify": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", - "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.2" - } - }, "node_modules/dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", @@ -7241,14 +7322,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/futoin-hkdf": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz", - "integrity": "sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -7538,6 +7611,11 @@ "node": ">= 0.4" } }, + "node_modules/hookified": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.8.1.tgz", + "integrity": "sha512-GrO2l93P8xCWBSTBX9l2BxI78VU/MAAYag+pG8curS3aBGy0++ZlxrQ7PdUOUVMbn5BwkGb6+eRrnf43ipnFEA==" + }, "node_modules/htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -8656,6 +8734,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/mpg123-decoder/-/mpg123-decoder-1.0.0.tgz", "integrity": "sha512-WV+pyuMUhRqv7s8S6p/Ii4KQHdBD1pb3yaABxcKJRsNp+HQ/Y6z2iIBIaOZu0JMHPTOoICYt0REDZ7XfLu+n/g==", + "optional": true, + "peer": true, "dependencies": { "@wasm-audio-decoders/common": "9.0.5" }, @@ -8822,6 +8902,8 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/node-wav/-/node-wav-0.0.2.tgz", "integrity": "sha512-M6Rm/bbG6De/gKGxOpeOobx/dnGuP0dz40adqx38boqHhlWssBJZgLCPBNtb9NkrmnKYiV04xELq+R6PFOnoLA==", + "optional": true, + "peer": true, "engines": { "node": ">=4.4.0" } @@ -8948,6 +9030,8 @@ "version": "1.6.14", "resolved": "https://registry.npmjs.org/ogg-opus-decoder/-/ogg-opus-decoder-1.6.14.tgz", "integrity": "sha512-RQpk9yFl/mqXFwcgf1BrEYWL92HZk++aU1fOO8mPZ1+1DUYbJdpdUQEFfbPE1xcBkRGU3p75DjEO+EDMNeikFQ==", + "optional": true, + "peer": true, "dependencies": { "@wasm-audio-decoders/common": "9.0.5", "codec-parser": "2.5.0", @@ -9060,6 +9144,8 @@ "version": "0.7.7", "resolved": "https://registry.npmjs.org/opus-decoder/-/opus-decoder-0.7.7.tgz", "integrity": "sha512-KWDyCi/9aXnNN+jrjs+aaVdwiwzDdac81S9ul0iv1CTs4+5K4VDZKuJjIImrYOBA2oSNHDjVq4xzn6BE+XbI1A==", + "optional": true, + "peer": true, "dependencies": { "@wasm-audio-decoders/common": "9.0.5" }, @@ -9788,6 +9874,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/qoa-format/-/qoa-format-1.0.1.tgz", "integrity": "sha512-dMB0Z6XQjdpz/Cw4Rf6RiBpQvUSPCfYlQMWvmuWlWkAT7nDQD29cVZ1SwDUB6DYJSitHENwbt90lqfI+7bvMcw==", + "optional": true, + "peer": true, "dependencies": { "@thi.ng/bitstream": "^2.2.12" } @@ -10687,6 +10775,8 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/simple-yenc/-/simple-yenc-1.0.4.tgz", "integrity": "sha512-5gvxpSd79e9a3V4QDYUqnqxeD4HGlhCakVpb6gMnDD7lexJggSBJRBO5h52y/iJrdXRilX9UCuDaIJhSWm5OWw==", + "optional": true, + "peer": true, "funding": { "type": "individual", "url": "https://github.com/sponsors/eshaz" @@ -10900,11 +10990,6 @@ "stream-chain": "^2.2.5" } }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", diff --git a/package.json b/package.json index 974f2a922..df949109d 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@sentry/node": "^8.47.0", "amqplib": "^0.10.5", "axios": "^1.7.9", - "baileys": "github:EvolutionAPI/Baileys", + "baileys": "github:mbap-dev/Baileys#v6.7.16", "class-validator": "^0.14.1", "compression": "^1.7.5", "cors": "^2.8.5",