Merge branch 'ev2' into v2.0.0

This commit is contained in:
Stênio Aníbal 2024-08-16 17:46:14 -03:00
commit fbff945d5b
25 changed files with 1070 additions and 470 deletions

View File

@ -3,8 +3,7 @@ SERVER_PORT=8080
# Server URL - Set your application url # Server URL - Set your application url
SERVER_URL=http://localhost:8080 SERVER_URL=http://localhost:8080
TELEMETRY=true SENTRY_DSN=
TELEMETRY_URL=
# Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com' # Cors - * for all or set separate by commas - ex.: 'yourdomain1.com, yourdomain2.com'
CORS_ORIGIN=* CORS_ORIGIN=*
@ -22,8 +21,6 @@ LOG_BAILEYS=error
# If you don't even want an expiration, enter the value false # If you don't even want an expiration, enter the value false
DEL_INSTANCE=false DEL_INSTANCE=false
# Permanent data storage
DATABASE_ENABLED=true
# Provider: postgresql | mysql # Provider: postgresql | mysql
DATABASE_PROVIDER=postgresql DATABASE_PROVIDER=postgresql
DATABASE_CONNECTION_URI='postgresql://user:pass@localhost:5432/evolution?schema=public' DATABASE_CONNECTION_URI='postgresql://user:pass@localhost:5432/evolution?schema=public'
@ -178,6 +175,7 @@ S3_SECRET_KEY=
S3_BUCKET=evolution S3_BUCKET=evolution
S3_PORT=443 S3_PORT=443
S3_ENDPOINT=s3.domain.com S3_ENDPOINT=s3.domain.com
S3_REGION=eu-west-3
S3_USE_SSL=true S3_USE_SSL=true
# AMAZON S3 - Environment variables # AMAZON S3 - Environment variables
@ -186,6 +184,7 @@ S3_USE_SSL=true
# S3_ACCESS_KEY=access_key_id # S3_ACCESS_KEY=access_key_id
# S3_SECRET_KEY=secret_access_key # S3_SECRET_KEY=secret_access_key
# S3_ENDPOINT=s3.amazonaws.com # region: s3.eu-west-3.amazonaws.com # S3_ENDPOINT=s3.amazonaws.com # region: s3.eu-west-3.amazonaws.com
# S3_REGION=eu-west-3
# MINIO Use SSL - Environment variables # MINIO Use SSL - Environment variables
# S3_ENABLED=true # S3_ENABLED=true

View File

@ -1,50 +1,42 @@
module.exports = { module.exports = {
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
sourceType: 'CommonJS', sourceType: 'CommonJS',
}, },
plugins: [ plugins: ['@typescript-eslint', 'simple-import-sort', 'import'],
'@typescript-eslint', extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
'simple-import-sort',
'import'
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended'
],
globals: { globals: {
Atomics: 'readonly', Atomics: 'readonly',
SharedArrayBuffer: 'readonly', SharedArrayBuffer: 'readonly',
}, },
root: true, root: true,
env: { env: {
node: true, node: true,
jest: true, jest: true,
}, },
ignorePatterns: ['.eslintrc.js'], ignorePatterns: ['.eslintrc.js'],
rules: { rules: {
'@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unused-vars': 'error', '@typescript-eslint/no-unused-vars': 'error',
'import/first': 'error', 'import/first': 'error',
'import/no-duplicates': 'error', 'import/no-duplicates': 'error',
'simple-import-sort/imports': 'error', 'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error', 'simple-import-sort/exports': 'error',
'@typescript-eslint/ban-types': [ '@typescript-eslint/ban-types': [
'error', 'error',
{ {
extendDefaults: true, extendDefaults: true,
types: { types: {
'{}': false, '{}': false,
Object: false, Object: false,
},
}, },
], },
'prettier/prettier': ['error', { endOfLine: 'auto' }], ],
'prettier/prettier': ['error', { endOfLine: 'auto' }],
}, },
}; };

View File

@ -1,9 +1,23 @@
# 2.0.9 (pre release) # 2.0.10 (2024-08-16 16:23)
### Features
* OpenAI send images when markdown
* Dify send images when markdown
* Sentry implemented
### Fixed
* Fix on get profilePicture
* Added S3_REGION on minio settings
# 2.0.9 (2024-08-15 12:31)
### Features ### Features
* Added ignoreJids in chatwoot settings * Added ignoreJids in chatwoot settings
* Dify now identifies images * Dify now identifies images
* Openai now identifies images
### Fixed ### Fixed
@ -16,6 +30,9 @@
* Deprecate buttons and list in new Baileys version * Deprecate buttons and list in new Baileys version
* Changed labels to be unique on the same instance * Changed labels to be unique on the same instance
* Remove instance from redis even if using database * Remove instance from redis even if using database
* Unified integration session system so they don't overlap
* Temporary fix for pictureUrl bug in groups
* Fix on migrations
# 2.0.9-rc (2024-08-09 18:00) # 2.0.9-rc (2024-08-09 18:00)

View File

@ -10,16 +10,16 @@ if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]]
export DATABASE_URL export DATABASE_URL
echo "Deploying migrations for $DATABASE_PROVIDER" echo "Deploying migrations for $DATABASE_PROVIDER"
echo "Database URL: $DATABASE_URL" echo "Database URL: $DATABASE_URL"
rm -rf ./prisma/migrations # rm -rf ./prisma/migrations
cp -r ./prisma/$DATABASE_PROVIDER-migrations ./prisma/migrations # cp -r ./prisma/$DATABASE_PROVIDER-migrations ./prisma/migrations
npx prisma migrate deploy --schema ./prisma/$DATABASE_PROVIDER-schema.prisma npm run db:deploy
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Migration failed" echo "Migration failed"
exit 1 exit 1
else else
echo "Migration succeeded" echo "Migration succeeded"
fi fi
npx prisma generate --schema ./prisma/$DATABASE_PROVIDER-schema.prisma npm run db:generate
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Prisma generate failed" echo "Prisma generate failed"
exit 1 exit 1

View File

@ -10,7 +10,7 @@ if [[ "$DATABASE_PROVIDER" == "postgresql" || "$DATABASE_PROVIDER" == "mysql" ]]
export DATABASE_URL export DATABASE_URL
echo "Generating database for $DATABASE_PROVIDER" echo "Generating database for $DATABASE_PROVIDER"
echo "Database URL: $DATABASE_URL" echo "Database URL: $DATABASE_URL"
npx prisma generate --schema=prisma/$DATABASE_PROVIDER-schema.prisma npm run db:generate
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Prisma generate failed" echo "Prisma generate failed"
exit 1 exit 1

View File

@ -2,7 +2,7 @@ version: "3.7"
services: services:
evolution_v2: evolution_v2:
image: atendai/evolution-api:v2.0.9-rc image: atendai/evolution-api:v2.0.9
volumes: volumes:
- evolution_instances:/evolution/instances - evolution_instances:/evolution/instances
networks: networks:
@ -10,7 +10,6 @@ services:
environment: environment:
- SERVER_URL=https://evo2.site.com - SERVER_URL=https://evo2.site.com
- DEL_INSTANCE=false - DEL_INSTANCE=false
- DATABASE_ENABLED=true
- DATABASE_PROVIDER=postgresql - DATABASE_PROVIDER=postgresql
- DATABASE_CONNECTION_URI=postgresql://postgres:SENHA@postgres:5432/evolution - DATABASE_CONNECTION_URI=postgresql://postgres:SENHA@postgres:5432/evolution
- DATABASE_SAVE_DATA_INSTANCE=true - DATABASE_SAVE_DATA_INSTANCE=true

View File

@ -3,7 +3,7 @@ FROM node:20-alpine AS builder
RUN apk update && \ RUN apk update && \
apk add git ffmpeg wget curl bash apk add git ffmpeg wget curl bash
LABEL version="2.0.9-rc" description="Api to control whatsapp features through http requests." LABEL version="2.0.10" description="Api to control whatsapp features through http requests."
LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes"
LABEL contact="contato@agenciadgcode.com" LABEL contact="contato@agenciadgcode.com"
@ -18,6 +18,8 @@ COPY ./public ./public
COPY ./prisma ./prisma COPY ./prisma ./prisma
COPY ./manager ./manager COPY ./manager ./manager
COPY ./.env.example ./.env COPY ./.env.example ./.env
COPY ./runWithProvider.js ./
COPY ./tsup.config.ts ./
COPY ./Docker ./Docker COPY ./Docker ./Docker
@ -47,6 +49,8 @@ COPY --from=builder /evolution/manager ./manager
COPY --from=builder /evolution/public ./public COPY --from=builder /evolution/public ./public
COPY --from=builder /evolution/.env ./.env COPY --from=builder /evolution/.env ./.env
COPY --from=builder /evolution/Docker ./Docker COPY --from=builder /evolution/Docker ./Docker
COPY --from=builder /evolution/runWithProvider.js ./runWithProvider.js
COPY --from=builder /evolution/tsup.config.ts ./tsup.config.ts
ENV DOCKER_ENV=true ENV DOCKER_ENV=true

View File

@ -1,11 +1,11 @@
{ {
"name": "evolution-api", "name": "evolution-api",
"version": "2.0.9", "version": "2.0.10",
"description": "Rest api for communication with WhatsApp", "description": "Rest api for communication with WhatsApp",
"main": "./dist/main.js", "main": "./dist/main.js",
"type": "commonjs", "type": "commonjs",
"scripts": { "scripts": {
"build": "tsup", "build": "tsc --noEmit && tsup",
"start": "tsnd -r tsconfig-paths/register --files --transpile-only ./src/main.ts", "start": "tsnd -r tsconfig-paths/register --files --transpile-only ./src/main.ts",
"start:prod": "node dist/main", "start:prod": "node dist/main",
"dev:server": "clear && tsnd -r tsconfig-paths/register --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts", "dev:server": "clear && tsnd -r tsconfig-paths/register --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts",
@ -52,10 +52,11 @@
"@figuro/chatwoot-sdk": "^1.1.16", "@figuro/chatwoot-sdk": "^1.1.16",
"@hapi/boom": "^10.0.1", "@hapi/boom": "^10.0.1",
"@prisma/client": "^5.15.0", "@prisma/client": "^5.15.0",
"@sentry/node": "^7.59.2", "@sentry/node": "^7.119.0",
"@sentry/profiling-node": "^8.26.0",
"amqplib": "^0.10.3", "amqplib": "^0.10.3",
"axios": "^1.6.5", "axios": "^1.6.5",
"baileys": "6.7.6", "baileys": "6.7.5",
"class-validator": "^0.14.1", "class-validator": "^0.14.1",
"compression": "^1.7.4", "compression": "^1.7.4",
"cors": "^2.8.5", "cors": "^2.8.5",

View File

@ -1,151 +1,185 @@
/* /*
Warnings: Warnings:
- You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Chat` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Chatwoot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Contact` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Dify` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `DifySession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `DifySetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `disconnectionAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Instance` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Label` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Media` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `OpenaiBot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `OpenaiCreds` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `OpenaiSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `OpenaiSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Proxy` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Rabbitmq` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Session` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Setting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Sqs` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Template` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Typebot` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `TypebotSession` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `TypebotSetting` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Webhook` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `createdAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`.
- You are about to alter the column `updatedAt` on the `Websocket` table. The data in that column could be lost. The data in that column will be cast from `Timestamp(0)` to `Timestamp`. - A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Contact` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Contact` will be added. If there are existing duplicate values, this will fail.
*/ */
-- AlterTable -- AlterTable
ALTER TABLE `Chat` ADD COLUMN `name` VARCHAR(100) NULL, ALTER TABLE `Chat`
MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ADD COLUMN `name` VARCHAR(100) NULL,
MODIFY `updatedAt` TIMESTAMP NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Chatwoot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Chatwoot`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Contact` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Contact`
MODIFY `updatedAt` TIMESTAMP NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Dify` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Dify`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `DifySession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `DifySession`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `DifySetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `DifySetting`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Instance` MODIFY `disconnectionAt` TIMESTAMP NULL, ALTER TABLE `Instance`
MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, MODIFY `disconnectionAt` TIMESTAMP NULL,
MODIFY `updatedAt` TIMESTAMP NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Label` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Label`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Media` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; ALTER TABLE `Media`
MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP;
-- AlterTable -- AlterTable
ALTER TABLE `OpenaiBot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `OpenaiBot`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `OpenaiCreds` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `OpenaiCreds`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `OpenaiSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `OpenaiSession`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `OpenaiSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `OpenaiSetting`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Proxy` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Proxy`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Rabbitmq` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Rabbitmq`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Session` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP; ALTER TABLE `Session`
MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
-- AlterTable -- AlterTable
ALTER TABLE `Setting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Setting`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Sqs` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Sqs`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Template` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Template`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Typebot` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Typebot`
MODIFY `updatedAt` TIMESTAMP NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NULL;
-- AlterTable -- AlterTable
ALTER TABLE `TypebotSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `TypebotSession`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `TypebotSetting` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `TypebotSetting`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Webhook` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Webhook`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- AlterTable -- AlterTable
ALTER TABLE `Websocket` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, ALTER TABLE `Websocket`
MODIFY `updatedAt` TIMESTAMP NOT NULL; MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
MODIFY `updatedAt` TIMESTAMP NOT NULL;
-- Remove the duplicates
DELETE c1
FROM `Contact` c1
INNER JOIN (
SELECT MIN(id) as id
FROM `Contact`
GROUP BY
`remoteJid`, `instanceId`
) c2 ON c1.`remoteJid` = c2.`remoteJid`
AND c1.`instanceId` = c2.`instanceId`
AND c1.id != c2.id;
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX `Contact_remoteJid_instanceId_key` ON `Contact`(`remoteJid`, `instanceId`); CREATE UNIQUE INDEX `Contact_remoteJid_instanceId_key` ON `Contact` (`remoteJid`, `instanceId`);

View File

@ -4,5 +4,14 @@
- A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Contact` will be added. If there are existing duplicate values, this will fail. - A unique constraint covering the columns `[remoteJid,instanceId]` on the table `Contact` will be added. If there are existing duplicate values, this will fail.
*/ */
-- Remove the duplicates
DELETE FROM "Contact"
WHERE ctid NOT IN (
SELECT min(ctid)
FROM "Contact"
GROUP BY "remoteJid", "instanceId"
);
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "Contact_remoteJid_instanceId_key" ON "Contact"("remoteJid", "instanceId"); CREATE UNIQUE INDEX "Contact_remoteJid_instanceId_key" ON "Contact"("remoteJid", "instanceId");

View File

@ -538,7 +538,7 @@ export class InstanceController {
if (state == 'close') { if (state == 'close') {
await instance.connectToWhatsapp(number); await instance.connectToWhatsapp(number);
await delay(5000); await delay(2000);
return instance.qrCode; return instance.qrCode;
} }

View File

@ -1,11 +1,4 @@
import { import { proto, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from 'baileys';
proto,
WAPresence,
WAPrivacyGroupAddValue,
WAPrivacyOnlineValue,
WAPrivacyValue,
WAReadReceiptsValue,
} from 'baileys';
export class OnWhatsAppDto { export class OnWhatsAppDto {
constructor( constructor(
@ -91,7 +84,7 @@ export class PrivacySettingDto {
status: WAPrivacyValue; status: WAPrivacyValue;
online: WAPrivacyOnlineValue; online: WAPrivacyOnlineValue;
last: WAPrivacyValue; last: WAPrivacyValue;
groupadd: WAPrivacyGroupAddValue; groupadd: WAPrivacyValue;
} }
export class DeleteMessage { export class DeleteMessage {

View File

@ -34,7 +34,7 @@ async function apikey(req: Request, _: Response, next: NextFunction) {
return next(); return next();
} }
} else { } else {
if (req.originalUrl.includes('/instance/fetchInstances') && db.ENABLED) { if (req.originalUrl.includes('/instance/fetchInstances') && db.SAVE_DATA.INSTANCE) {
const instanceByKey = await prismaRepository.instance.findFirst({ const instanceByKey = await prismaRepository.instance.findFirst({
where: { token: key }, where: { token: key },
}); });

View File

@ -1,13 +1,12 @@
import { InstanceDto } from '@api/dto/instance.dto'; import { InstanceDto } from '@api/dto/instance.dto';
import { cache, waMonitor } from '@api/server.module'; import { cache, waMonitor } from '@api/server.module';
import { CacheConf, configService, Database } from '@config/env.config'; import { CacheConf, configService } from '@config/env.config';
import { BadRequestException, ForbiddenException, InternalServerErrorException, NotFoundException } from '@exceptions'; import { BadRequestException, ForbiddenException, InternalServerErrorException, NotFoundException } from '@exceptions';
import { prismaServer } from '@libs/prisma.connect'; import { prismaServer } from '@libs/prisma.connect';
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
async function getInstance(instanceName: string) { async function getInstance(instanceName: string) {
try { try {
const db = configService.get<Database>('DATABASE');
const cacheConf = configService.get<CacheConf>('CACHE'); const cacheConf = configService.get<CacheConf>('CACHE');
const exists = !!waMonitor.waInstances[instanceName]; const exists = !!waMonitor.waInstances[instanceName];
@ -18,13 +17,9 @@ async function getInstance(instanceName: string) {
return exists || keyExists; return exists || keyExists;
} }
if (db.ENABLED) { const prisma = prismaServer;
const prisma = prismaServer;
return exists || (await prisma.instance.findMany({ where: { name: instanceName } })).length > 0; return exists || (await prisma.instance.findMany({ where: { name: instanceName } })).length > 0;
}
return false;
} catch (error) { } catch (error) {
throw new InternalServerErrorException(error?.toString()); throw new InternalServerErrorException(error?.toString());
} }

View File

@ -354,7 +354,7 @@ export class ChatwootService {
return contact; return contact;
} catch (error) { } catch (error) {
this.logger.error(error); return null;
} }
} }

View File

@ -289,7 +289,12 @@ class ChatwootImport {
this.deleteHistoryMessages(instance); this.deleteHistoryMessages(instance);
this.deleteRepositoryMessagesCache(instance); this.deleteRepositoryMessagesCache(instance);
this.importHistoryContacts(instance, provider); const providerData: ChatwootDto = {
...provider,
ignoreJids: Array.isArray(provider.ignoreJids) ? provider.ignoreJids.map((event) => String(event)) : [],
};
this.importHistoryContacts(instance, providerData);
return totalMessagesImported; return totalMessagesImported;
} catch (error) { } catch (error) {

View File

@ -1101,7 +1101,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.query = contentSplit[2]; payload.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1118,14 +1118,51 @@ export class DifyService {
const message = response?.data?.answer; const message = response?.data?.answer;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1169,7 +1206,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.inputs.query = contentSplit[2]; payload.inputs.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1186,14 +1223,51 @@ export class DifyService {
const message = response?.data?.answer; const message = response?.data?.answer;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1237,7 +1311,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.query = contentSplit[2]; payload.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1274,14 +1348,51 @@ export class DifyService {
const message = response?.data?.answer; const message = response?.data?.answer;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1329,7 +1440,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.inputs.query = contentSplit[2]; payload.inputs.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1346,14 +1457,51 @@ export class DifyService {
const message = response?.data?.data.outputs.text; const message = response?.data?.data.outputs.text;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
if (settings.keepOpen) { if (settings.keepOpen) {
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
@ -1506,7 +1654,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.query = contentSplit[2]; payload.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1523,14 +1671,51 @@ export class DifyService {
const message = response?.data?.answer; const message = response?.data?.answer;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1574,7 +1759,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.inputs.query = contentSplit[2]; payload.inputs.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1591,14 +1776,51 @@ export class DifyService {
const message = response?.data?.answer; const message = response?.data?.answer;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1642,7 +1864,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.query = contentSplit[2]; payload.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1741,7 +1963,7 @@ export class DifyService {
url: contentSplit[1].split('?')[0], url: contentSplit[1].split('?')[0],
}, },
]; ];
payload.inputs.query = contentSplit[2]; payload.inputs.query = contentSplit[2] || content;
} }
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1758,14 +1980,51 @@ export class DifyService {
const message = response?.data?.data.outputs.text; const message = response?.data?.data.outputs.text;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
if (settings.keepOpen) { if (settings.keepOpen) {
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({

View File

@ -874,11 +874,27 @@ export class OpenaiService {
: msg?.message?.audioMessage : msg?.message?.audioMessage
? `audioMessage|${mediaId}` ? `audioMessage|${mediaId}`
: undefined, : undefined,
imageMessage: msg?.message?.imageMessage ? `imageMessage|${mediaId}` : undefined, imageMessage: msg?.message?.imageMessage
videoMessage: msg?.message?.videoMessage ? `videoMessage|${mediaId}` : undefined, ? `imageMessage|${mediaId}${
documentMessage: msg?.message?.documentMessage ? `documentMessage|${mediaId}` : undefined, msg?.message?.imageMessage?.caption ? `|${msg?.message?.imageMessage?.caption}` : ''
documentWithCaptionMessage: msg?.message?.auddocumentWithCaptionMessageioMessage }`
? `documentWithCaptionMessage|${mediaId}` : undefined,
videoMessage: msg?.message?.videoMessage
? `videoMessage|${mediaId}${
msg?.message?.videoMessage?.caption ? `|${msg?.message?.videoMessage?.caption}` : ''
}`
: undefined,
documentMessage: msg?.message?.documentMessage
? `documentMessage|${mediaId}${
msg?.message?.documentMessage?.caption ? `|${msg?.message?.documentMessage?.caption}` : ''
}`
: undefined,
documentWithCaptionMessage: msg?.message?.documentWithCaptionMessage?.message?.documentMessage
? `documentWithCaptionMessage|${mediaId}${
msg?.message?.documentWithCaptionMessage?.message?.documentMessage?.caption
? `|${msg?.message?.documentWithCaptionMessage?.message?.documentMessage?.caption}`
: ''
}`
: undefined, : undefined,
}; };
@ -1303,10 +1319,28 @@ export class OpenaiService {
session = data.session; session = data.session;
} }
await this.client.beta.threads.messages.create(data.session.sessionId, { const messageData: any = {
role: 'user', role: 'user',
content, content: [{ type: 'text', text: content }],
}); };
if (this.isImageMessage(content)) {
const contentSplit = content.split('|');
const url = contentSplit[1].split('?')[0];
messageData.content = [
{ type: 'text', text: contentSplit[2] || content },
{
type: 'image_url',
image_url: {
url: url,
},
},
];
}
await this.client.beta.threads.messages.create(data.session.sessionId, messageData);
const runAssistant = await this.client.beta.threads.runs.create(data.session.sessionId, { const runAssistant = await this.client.beta.threads.runs.create(data.session.sessionId, {
assistant_id: openaiBot.assistantId, assistant_id: openaiBot.assistantId,
@ -1322,14 +1356,51 @@ export class OpenaiService {
const message = response?.data[0].content[0].text.value; const message = response?.data[0].content[0].text.value;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1420,6 +1491,10 @@ export class OpenaiService {
} }
} }
private isImageMessage(content: string) {
return content.includes('imageMessage');
}
private async processOpenaiAssistant( private async processOpenaiAssistant(
instance: any, instance: any,
remoteJid: string, remoteJid: string,
@ -1531,10 +1606,28 @@ export class OpenaiService {
const threadId = session.sessionId; const threadId = session.sessionId;
await this.client.beta.threads.messages.create(threadId, { const messageData: any = {
role: 'user', role: 'user',
content, content: [{ type: 'text', text: content }],
}); };
if (this.isImageMessage(content)) {
const contentSplit = content.split('|');
const url = contentSplit[1].split('?')[0];
messageData.content = [
{ type: 'text', text: contentSplit[2] || content },
{
type: 'image_url',
image_url: {
url: url,
},
},
];
}
await this.client.beta.threads.messages.create(threadId, messageData);
const runAssistant = await this.client.beta.threads.runs.create(threadId, { const runAssistant = await this.client.beta.threads.runs.create(threadId, {
assistant_id: openaiBot.assistantId, assistant_id: openaiBot.assistantId,
@ -1550,14 +1643,51 @@ export class OpenaiService {
const message = response?.data[0].content[0].text.value; const message = response?.data[0].content[0].text.value;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1654,15 +1784,28 @@ export class OpenaiService {
}; };
}); });
const messages: any[] = [ const messageData: any = {
...messagesSystem, role: 'user',
...messagesAssistant, content: [{ type: 'text', text: content }],
...messagesUser, };
{
role: 'user', if (this.isImageMessage(content)) {
content: content, const contentSplit = content.split('|');
},
]; const url = contentSplit[1].split('?')[0];
messageData.content = [
{ type: 'text', text: contentSplit[2] || content },
{
type: 'image_url',
image_url: {
url: url,
},
},
];
}
const messages: any[] = [...messagesSystem, ...messagesAssistant, ...messagesUser, messageData];
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1678,14 +1821,51 @@ export class OpenaiService {
const message = completions.choices[0].message.content; const message = completions.choices[0].message.content;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {
@ -1838,15 +2018,28 @@ export class OpenaiService {
}; };
}); });
const messages: any[] = [ const messageData: any = {
...messagesSystem, role: 'user',
...messagesAssistant, content: [{ type: 'text', text: content }],
...messagesUser, };
{
role: 'user', if (this.isImageMessage(content)) {
content: content, const contentSplit = content.split('|');
},
]; const url = contentSplit[1].split('?')[0];
messageData.content = [
{ type: 'text', text: contentSplit[2] || content },
{
type: 'image_url',
image_url: {
url: url,
},
},
];
}
const messages: any[] = [...messagesSystem, ...messagesAssistant, ...messagesUser, messageData];
await instance.client.presenceSubscribe(remoteJid); await instance.client.presenceSubscribe(remoteJid);
@ -1862,14 +2055,51 @@ export class OpenaiService {
const message = completions.choices[0].message.content; const message = completions.choices[0].message.content;
await instance.textMessage( const regex = /!?\[(.*?)\]\((.*?)\)/g;
{
number: remoteJid.split('@')[0], const result = [];
delay: settings?.delayMessage || 1000, let lastIndex = 0;
text: message,
}, let match;
false, while ((match = regex.exec(message)) !== null) {
); if (match.index > lastIndex) {
result.push({ text: message.slice(lastIndex, match.index).trim() });
}
result.push({ caption: match[1], url: match[2] });
lastIndex = regex.lastIndex;
}
if (lastIndex < message.length) {
result.push({ text: message.slice(lastIndex).trim() });
}
for (const item of result) {
if (item.text) {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
text: item.text,
},
false,
);
}
if (item.url) {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
delay: settings?.delayMessage || 1000,
mediatype: 'image',
media: item.url,
caption: item.caption,
},
false,
);
}
}
await this.prismaRepository.integrationSession.update({ await this.prismaRepository.integrationSession.update({
where: { where: {

View File

@ -21,6 +21,7 @@ const minioClient = (() => {
useSSL: BUCKET.USE_SSL, useSSL: BUCKET.USE_SSL,
accessKey: BUCKET.ACCESS_KEY, accessKey: BUCKET.ACCESS_KEY,
secretKey: BUCKET.SECRET_KEY, secretKey: BUCKET.SECRET_KEY,
region: BUCKET.REGION,
}); });
} }
})(); })();

View File

@ -68,7 +68,6 @@ import {
S3, S3,
Typebot, Typebot,
} from '@config/env.config'; } from '@config/env.config';
import { INSTANCE_DIR } from '@config/path.config';
import { BadRequestException, InternalServerErrorException, NotFoundException } from '@exceptions'; import { BadRequestException, InternalServerErrorException, NotFoundException } from '@exceptions';
import ffmpegPath from '@ffmpeg-installer/ffmpeg'; import ffmpegPath from '@ffmpeg-installer/ffmpeg';
import { Boom } from '@hapi/boom'; import { Boom } from '@hapi/boom';
@ -98,6 +97,7 @@ import makeWASocket, {
GroupParticipant, GroupParticipant,
isJidBroadcast, isJidBroadcast,
isJidGroup, isJidGroup,
// isJidNewsletter,
isJidUser, isJidUser,
makeCacheableSignalKeyStore, makeCacheableSignalKeyStore,
MessageUpsertType, MessageUpsertType,
@ -118,10 +118,8 @@ import { LabelAssociation } from 'baileys/lib/Types/LabelAssociation';
import { isBase64, isURL } from 'class-validator'; import { isBase64, isURL } from 'class-validator';
import { randomBytes } from 'crypto'; import { randomBytes } from 'crypto';
import EventEmitter2 from 'eventemitter2'; import EventEmitter2 from 'eventemitter2';
// import { exec } from 'child_process';
import ffmpeg from 'fluent-ffmpeg'; import ffmpeg from 'fluent-ffmpeg';
// import ffmpeg from 'fluent-ffmpeg'; import { readFileSync } from 'fs';
import { existsSync, readFileSync } from 'fs';
import Long from 'long'; import Long from 'long';
import mime from 'mime'; import mime from 'mime';
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
@ -148,7 +146,7 @@ export class BaileysStartupService extends ChannelStartupService {
) { ) {
super(configService, eventEmitter, prismaRepository, chatwootCache); super(configService, eventEmitter, prismaRepository, chatwootCache);
this.instance.qrcode = { count: 0 }; this.instance.qrcode = { count: 0 };
this.recoveringMessages(); // this.recoveringMessages();
this.authStateProvider = new AuthStateProvider(this.providerFiles); this.authStateProvider = new AuthStateProvider(this.providerFiles);
} }
@ -163,57 +161,57 @@ export class BaileysStartupService extends ChannelStartupService {
public phoneNumber: string; public phoneNumber: string;
private async recoveringMessages() { // private async recoveringMessages() {
const cacheConf = this.configService.get<CacheConf>('CACHE'); // const cacheConf = this.configService.get<CacheConf>('CACHE');
if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) { // if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) {
this.logger.info('Recovering messages lost from cache'); // this.logger.info('Recovering messages lost from cache');
setInterval(async () => { // setInterval(async () => {
this.baileysCache.keys().then((keys) => { // this.baileysCache.keys().then((keys) => {
keys.forEach(async (key) => { // keys.forEach(async (key) => {
const data = await this.baileysCache.get(key.split(':')[2]); // const data = await this.baileysCache.get(key.split(':')[2]);
let message: any; // let message: any;
let retry: number; // let retry: number;
if (!data?.message) { // if (!data?.message) {
message = data; // message = data;
retry = 0; // retry = 0;
} else { // } else {
message = data.message; // message = data.message;
retry = data.retry; // retry = data.retry;
} // }
if (message.messageStubParameters && message.messageStubParameters[0] === 'Message absent from node') { // if (message.messageStubParameters && message.messageStubParameters[0] === 'Message absent from node') {
retry = retry + 1; // retry = retry + 1;
this.logger.info(`Message absent from node, retrying to send, key: ${key.split(':')[2]} retry: ${retry}`); // this.logger.info(`Message absent from node, retrying to send, key: ${key.split(':')[2]} retry: ${retry}`);
if (message.messageStubParameters[1]) { // if (message.messageStubParameters[1]) {
await this.client.sendMessageAck(JSON.parse(message.messageStubParameters[1], BufferJSON.reviver)); // await this.client.sendMessageAck(JSON.parse(message.messageStubParameters[1], BufferJSON.reviver));
} // }
this.baileysCache.set(key.split(':')[2], { message, retry }); // this.baileysCache.set(key.split(':')[2], { message, retry });
if (retry >= 100) { // if (retry >= 100) {
this.logger.warn(`Message absent from node, retry limit reached, key: ${key.split(':')[2]}`); // this.logger.warn(`Message absent from node, retry limit reached, key: ${key.split(':')[2]}`);
this.baileysCache.delete(key.split(':')[2]); // this.baileysCache.delete(key.split(':')[2]);
return; // return;
} // }
} // }
}); // });
}); // });
// 15 minutes // // 15 minutes
}, 15 * 60 * 1000); // }, 15 * 60 * 1000);
} // }
} // }
private async forceUpdateGroupMetadataCache() { // private async forceUpdateGroupMetadataCache() {
this.logger.verbose('Force update group metadata cache'); // this.logger.verbose('Force update group metadata cache');
const groups = await this.fetchAllGroups({ getParticipants: 'false' }); // const groups = await this.fetchAllGroups({ getParticipants: 'false' });
for (const group of groups) { // for (const group of groups) {
await this.updateGroupMetadataCache(group.id); // await this.updateGroupMetadataCache(group.id);
} // }
} // }
public get connectionStatus() { public get connectionStatus() {
return this.stateConnection; return this.stateConnection;
@ -239,21 +237,12 @@ export class BaileysStartupService extends ChannelStartupService {
public async getProfileName() { public async getProfileName() {
let profileName = this.client.user?.name ?? this.client.user?.verifiedName; let profileName = this.client.user?.name ?? this.client.user?.verifiedName;
if (!profileName) { if (!profileName) {
if (this.configService.get<Database>('DATABASE').ENABLED) { const data = await this.prismaRepository.session.findUnique({
const data = await this.prismaRepository.session.findUnique({ where: { sessionId: this.instanceId },
where: { sessionId: this.instanceId }, });
});
if (data) { if (data) {
const creds = JSON.parse(JSON.stringify(data.creds), BufferJSON.reviver); const creds = JSON.parse(JSON.stringify(data.creds), BufferJSON.reviver);
profileName = creds.me?.name || creds.me?.verifiedName;
}
} else if (existsSync(join(INSTANCE_DIR, this.instanceName, 'creds.json'))) {
const creds = JSON.parse(
readFileSync(join(INSTANCE_DIR, this.instanceName, 'creds.json'), {
encoding: 'utf-8',
}),
);
profileName = creds.me?.name || creds.me?.verifiedName; profileName = creds.me?.name || creds.me?.verifiedName;
} }
} }
@ -404,17 +393,15 @@ export class BaileysStartupService extends ChannelStartupService {
disconnectionObject: JSON.stringify(lastDisconnect), disconnectionObject: JSON.stringify(lastDisconnect),
}); });
if (this.configService.get<Database>('DATABASE').ENABLED) { await this.prismaRepository.instance.update({
await this.prismaRepository.instance.update({ where: { id: this.instanceId },
where: { id: this.instanceId }, data: {
data: { connectionStatus: 'close',
connectionStatus: 'close', disconnectionAt: new Date(),
disconnectionAt: new Date(), disconnectionReasonCode: statusCode,
disconnectionReasonCode: statusCode, disconnectionObject: JSON.stringify(lastDisconnect),
disconnectionObject: JSON.stringify(lastDisconnect), },
}, });
});
}
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot.enabled) { if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp( this.chatwootService.eventWhatsapp(
@ -462,17 +449,15 @@ export class BaileysStartupService extends ChannelStartupService {
`, `,
); );
if (this.configService.get<Database>('DATABASE').ENABLED) { await this.prismaRepository.instance.update({
await this.prismaRepository.instance.update({ where: { id: this.instanceId },
where: { id: this.instanceId }, data: {
data: { ownerJid: this.instance.wuid,
ownerJid: this.instance.wuid, profileName: (await this.getProfileName()) as string,
profileName: (await this.getProfileName()) as string, profilePicUrl: this.instance.profilePictureUrl,
profilePicUrl: this.instance.profilePictureUrl, connectionStatus: 'open',
connectionStatus: 'open', },
}, });
});
}
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot.enabled) { if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp( this.chatwootService.eventWhatsapp(
@ -520,6 +505,7 @@ export class BaileysStartupService extends ChannelStartupService {
return webMessageInfo[0].message; return webMessageInfo[0].message;
} catch (error) { } catch (error) {
this.logger.error('line 508');
return { conversation: '' }; return { conversation: '' };
} }
} }
@ -539,7 +525,7 @@ export class BaileysStartupService extends ChannelStartupService {
return await useMultiFileAuthStateRedisDb(this.instance.id, this.cache); return await useMultiFileAuthStateRedisDb(this.instance.id, this.cache);
} }
if (db.SAVE_DATA.INSTANCE && db.ENABLED) { if (db.SAVE_DATA.INSTANCE) {
return await useMultiFileAuthStatePrisma(this.instance.id, this.cache); return await useMultiFileAuthStatePrisma(this.instance.id, this.cache);
} }
} }
@ -619,56 +605,40 @@ export class BaileysStartupService extends ChannelStartupService {
const socketConfig: UserFacingSocketConfig = { const socketConfig: UserFacingSocketConfig = {
...options, ...options,
version,
logger: P({ level: this.logBaileys }),
printQRInTerminal: false,
auth: { auth: {
creds: this.instance.authState.state.creds, creds: this.instance.authState.state.creds,
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any), keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any),
}, },
logger: P({ level: this.logBaileys }), msgRetryCounterCache: this.msgRetryCounterCache,
printQRInTerminal: false, generateHighQualityLinkPreview: true,
getMessage: async (key) => (await this.getMessage(key)) as Promise<proto.IMessage>,
...browserOptions, ...browserOptions,
version,
markOnlineOnConnect: this.localSettings.alwaysOnline, markOnlineOnConnect: this.localSettings.alwaysOnline,
retryRequestDelayMs: 350, retryRequestDelayMs: 350,
maxMsgRetryCount: 4, maxMsgRetryCount: 4,
fireInitQueries: true, fireInitQueries: true,
connectTimeoutMs: 20_000, connectTimeoutMs: 30_000,
keepAliveIntervalMs: 30_000, keepAliveIntervalMs: 30_000,
qrTimeout: 45_000, qrTimeout: 45_000,
emitOwnEvents: false, emitOwnEvents: false,
shouldIgnoreJid: (jid) => { shouldIgnoreJid: (jid) => {
const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid); const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid);
const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid); const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid);
const isNewsletter = jid ? jid.includes('newsletter') : false; // const isNewsletter = !isJidNewsletter(jid);
const isNewsletter = jid && jid.includes('newsletter');
return isGroupJid || isBroadcast || isNewsletter; return isGroupJid || isBroadcast || isNewsletter;
}, },
msgRetryCounterCache: this.msgRetryCounterCache,
getMessage: async (key) => (await this.getMessage(key)) as Promise<proto.IMessage>,
generateHighQualityLinkPreview: true,
syncFullHistory: this.localSettings.syncFullHistory, syncFullHistory: this.localSettings.syncFullHistory,
shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => {
return this.historySyncNotification(msg); return this.historySyncNotification(msg);
}, },
// cachedGroupMetadata: this.getGroupMetadataCache,
userDevicesCache: this.userDevicesCache, userDevicesCache: this.userDevicesCache,
transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 }, transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 },
patchMessageBeforeSending(message) {
if (
message.deviceSentMessage?.message?.listMessage?.listType === proto.Message.ListMessage.ListType.PRODUCT_LIST
) {
message = JSON.parse(JSON.stringify(message));
message.deviceSentMessage.message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT;
}
if (message.listMessage?.listType == proto.Message.ListMessage.ListType.PRODUCT_LIST) {
message = JSON.parse(JSON.stringify(message));
message.listMessage.listType = proto.Message.ListMessage.ListType.SINGLE_SELECT;
}
return message;
},
forceGroupsPrekeys: false,
}; };
this.endSession = false; this.endSession = false;
@ -693,6 +663,7 @@ export class BaileysStartupService extends ChannelStartupService {
return await this.createClient(number); return await this.createClient(number);
} catch (error) { } catch (error) {
this.logger.error('line 667');
this.logger.error(error); this.logger.error(error);
throw new InternalServerErrorException(error?.toString()); throw new InternalServerErrorException(error?.toString());
} }
@ -702,6 +673,7 @@ export class BaileysStartupService extends ChannelStartupService {
try { try {
return await this.createClient(this.phoneNumber); return await this.createClient(this.phoneNumber);
} catch (error) { } catch (error) {
this.logger.error('line 677');
this.logger.error(error); this.logger.error(error);
throw new InternalServerErrorException(error?.toString()); throw new InternalServerErrorException(error?.toString());
} }
@ -819,7 +791,7 @@ export class BaileysStartupService extends ChannelStartupService {
if (updatedContacts.length > 0) { if (updatedContacts.length > 0) {
await Promise.all( await Promise.all(
updatedContacts.map(async function (contact) { updatedContacts.map(async (contact) => {
const update = this.prismaRepository.contact.updateMany({ const update = this.prismaRepository.contact.updateMany({
where: { remoteJid: contact.remoteJid, instanceId: this.instanceId }, where: { remoteJid: contact.remoteJid, instanceId: this.instanceId },
data: { data: {
@ -829,7 +801,7 @@ export class BaileysStartupService extends ChannelStartupService {
const instance = { instanceName: this.instance.name, instanceId: this.instance.id }; const instance = { instanceName: this.instance.name, instanceId: this.instance.id };
const findParticipant = await this.findContact(instance, contact.remoteJid.split('@')[0]); const findParticipant = await this.chatwootService.findContact(instance, contact.remoteJid.split('@')[0]);
this.chatwootService.updateContact(instance, findParticipant.id, { this.chatwootService.updateContact(instance, findParticipant.id, {
name: contact.pushName, name: contact.pushName,
@ -841,6 +813,7 @@ export class BaileysStartupService extends ChannelStartupService {
); );
} }
} catch (error) { } catch (error) {
this.logger.error('line 817');
this.logger.error(`Error: ${error.message}`); this.logger.error(`Error: ${error.message}`);
} }
}, },
@ -879,13 +852,25 @@ export class BaileysStartupService extends ChannelStartupService {
messages, messages,
chats, chats,
contacts, contacts,
isLatest,
progress,
syncType,
}: { }: {
chats: Chat[]; chats: Chat[];
contacts: Contact[]; contacts: Contact[];
messages: proto.IWebMessageInfo[]; messages: proto.IWebMessageInfo[];
isLatest: boolean; isLatest?: boolean;
progress?: number;
syncType?: proto.HistorySync.HistorySyncType;
}) => { }) => {
try { try {
if (syncType === proto.HistorySync.HistorySyncType.ON_DEMAND) {
console.log('received on-demand history sync, messages=', messages);
}
console.log(
`recv ${chats.length} chats, ${contacts.length} contacts, ${messages.length} msgs (is latest: ${isLatest}, progress: ${progress}%), type: ${syncType}`,
);
const instance: InstanceDto = { instanceName: this.instance.name }; const instance: InstanceDto = { instanceName: this.instance.name };
let timestampLimitToImport = null; let timestampLimitToImport = null;
@ -1022,6 +1007,7 @@ export class BaileysStartupService extends ChannelStartupService {
messages = undefined; messages = undefined;
chats = undefined; chats = undefined;
} catch (error) { } catch (error) {
this.logger.error('line 1011');
this.logger.error(error); this.logger.error(error);
} }
}, },
@ -1030,14 +1016,31 @@ export class BaileysStartupService extends ChannelStartupService {
{ {
messages, messages,
type, type,
requestId,
}: { }: {
messages: proto.IWebMessageInfo[]; messages: proto.IWebMessageInfo[];
type: MessageUpsertType; type: MessageUpsertType;
requestId?: string;
}, },
settings: any, settings: any,
) => { ) => {
try { try {
for (const received of messages) { for (const received of messages) {
if (received.message?.conversation || received.message?.extendedTextMessage?.text) {
const text = received.message?.conversation || received.message?.extendedTextMessage?.text;
if (text == 'requestPlaceholder' && !requestId) {
// const messageId = await this.client.requestPlaceholderResend(received.key);
// console.log('requested placeholder resync, id=', messageId);
} else if (requestId) {
console.log('Message received from phone, id=', requestId, received);
}
if (text == 'onDemandHistSync') {
// const messageId = await this.client.fetchMessageHistory(50, received.key, received.messageTimestamp!);
// console.log('requested on-demand sync, id=', messageId);
}
}
if (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) { if (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) {
const editedMessage = const editedMessage =
received.message?.protocolMessage || received.message?.editedMessage?.message?.protocolMessage; received.message?.protocolMessage || received.message?.editedMessage?.message?.protocolMessage;
@ -1156,7 +1159,7 @@ export class BaileysStartupService extends ChannelStartupService {
const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName); const fullName = join(`${this.instance.id}`, received.key.remoteJid, mediaType, fileName);
await s3Service.uploadFile(fullName, buffer, size.fileLength, { await s3Service.uploadFile(fullName, buffer, size.fileLength?.low, {
'Content-Type': mimetype, 'Content-Type': mimetype,
}); });
@ -1174,6 +1177,7 @@ export class BaileysStartupService extends ChannelStartupService {
messageRaw.message.mediaUrl = mediaUrl; messageRaw.message.mediaUrl = mediaUrl;
} catch (error) { } catch (error) {
this.logger.error('line 1181');
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]); this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
} }
} }
@ -1310,6 +1314,7 @@ export class BaileysStartupService extends ChannelStartupService {
}); });
} }
} catch (error) { } catch (error) {
this.logger.error('line 1318');
this.logger.error(error); this.logger.error(error);
} }
}, },
@ -1488,7 +1493,7 @@ export class BaileysStartupService extends ChannelStartupService {
data: { association: LabelAssociation; type: 'remove' | 'add' }, data: { association: LabelAssociation; type: 'remove' | 'add' },
database: Database, database: Database,
) => { ) => {
if (database.ENABLED && database.SAVE_DATA.CHATS) { if (database.SAVE_DATA.CHATS) {
const chats = await this.prismaRepository.chat.findMany({ const chats = await this.prismaRepository.chat.findMany({
where: { instanceId: this.instanceId }, where: { instanceId: this.instanceId },
}); });
@ -1511,7 +1516,6 @@ export class BaileysStartupService extends ChannelStartupService {
} }
} }
// Envia dados para o webhook
this.sendDataWebhook(Events.LABELS_ASSOCIATION, { this.sendDataWebhook(Events.LABELS_ASSOCIATION, {
instance: this.instance.name, instance: this.instance.name,
type: data.type, type: data.type,
@ -1558,7 +1562,7 @@ export class BaileysStartupService extends ChannelStartupService {
if (events['messaging-history.set']) { if (events['messaging-history.set']) {
const payload = events['messaging-history.set']; const payload = events['messaging-history.set'];
this.messageHandle['messaging-history.set'](payload as any); this.messageHandle['messaging-history.set'](payload);
} }
if (events['messages.upsert']) { if (events['messages.upsert']) {
@ -1670,9 +1674,9 @@ export class BaileysStartupService extends ChannelStartupService {
public async profilePicture(number: string) { public async profilePicture(number: string) {
const jid = this.createJid(number); const jid = this.createJid(number);
const profilePictureUrl = await this.client.profilePictureUrl(jid, 'image');
try { try {
const profilePictureUrl = await this.client.profilePictureUrl(jid, 'image');
return { return {
wuid: jid, wuid: jid,
profilePictureUrl, profilePictureUrl,
@ -1771,11 +1775,11 @@ export class BaileysStartupService extends ChannelStartupService {
}; };
if (isJidGroup(sender)) { if (isJidGroup(sender)) {
option.useCachedGroupMetadata = true;
if (participants) if (participants)
option.cachedGroupMetadata = async () => { option.cachedGroupMetadata = async () => {
return { participants: participants as GroupParticipant[] }; return { participants: participants as GroupParticipant[] };
}; };
else option.cachedGroupMetadata = this.getGroupMetadataCache;
} }
if (ephemeralExpiration) option.ephemeralExpiration = ephemeralExpiration; if (ephemeralExpiration) option.ephemeralExpiration = ephemeralExpiration;
@ -2002,7 +2006,7 @@ export class BaileysStartupService extends ChannelStartupService {
quoted, quoted,
null, null,
group?.ephemeralDuration, group?.ephemeralDuration,
group.participants, // group?.participants,
); );
} else { } else {
messageSent = await this.sendMessage(sender, message, mentions, linkPreview, quoted); messageSent = await this.sendMessage(sender, message, mentions, linkPreview, quoted);
@ -2073,6 +2077,7 @@ export class BaileysStartupService extends ChannelStartupService {
return messageSent; return messageSent;
} catch (error) { } catch (error) {
this.logger.error('line 2081');
this.logger.error(error); this.logger.error(error);
throw new BadRequestException(error.toString()); throw new BadRequestException(error.toString());
} }
@ -2125,6 +2130,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { presence: data.presence }; return { presence: data.presence };
} catch (error) { } catch (error) {
this.logger.error('line 2134');
this.logger.error(error); this.logger.error(error);
throw new BadRequestException(error.toString()); throw new BadRequestException(error.toString());
} }
@ -2137,6 +2143,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { presence: data.presence }; return { presence: data.presence };
} catch (error) { } catch (error) {
this.logger.error('line 2147');
this.logger.error(error); this.logger.error(error);
throw new BadRequestException(error.toString()); throw new BadRequestException(error.toString());
} }
@ -2367,6 +2374,7 @@ export class BaileysStartupService extends ChannelStartupService {
{ userJid: this.instance.wuid }, { userJid: this.instance.wuid },
); );
} catch (error) { } catch (error) {
this.logger.error('line 2378');
this.logger.error(error); this.logger.error(error);
throw new InternalServerErrorException(error?.toString() || error); throw new InternalServerErrorException(error?.toString() || error);
} }
@ -2408,6 +2416,7 @@ export class BaileysStartupService extends ChannelStartupService {
return webpBuffer; return webpBuffer;
} catch (error) { } catch (error) {
this.logger.error('line 2420');
console.error('Erro ao converter a imagem para WebP:', error); console.error('Erro ao converter a imagem para WebP:', error);
throw error; throw error;
} }
@ -2805,6 +2814,7 @@ export class BaileysStartupService extends ChannelStartupService {
await this.client.readMessages(keys); await this.client.readMessages(keys);
return { message: 'Read messages', read: 'success' }; return { message: 'Read messages', read: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 2818');
throw new InternalServerErrorException('Read messages fail', error.toString()); throw new InternalServerErrorException('Read messages fail', error.toString());
} }
} }
@ -2870,6 +2880,7 @@ export class BaileysStartupService extends ChannelStartupService {
archived: true, archived: true,
}; };
} catch (error) { } catch (error) {
this.logger.error('line 2884');
throw new InternalServerErrorException({ throw new InternalServerErrorException({
archived: false, archived: false,
message: ['An error occurred while archiving the chat. Open a calling.', error.toString()], message: ['An error occurred while archiving the chat. Open a calling.', error.toString()],
@ -2907,6 +2918,7 @@ export class BaileysStartupService extends ChannelStartupService {
markedChatUnread: true, markedChatUnread: true,
}; };
} catch (error) { } catch (error) {
this.logger.error('line 2922');
throw new InternalServerErrorException({ throw new InternalServerErrorException({
markedChatUnread: false, markedChatUnread: false,
message: ['An error occurred while marked unread the chat. Open a calling.', error.toString()], message: ['An error occurred while marked unread the chat. Open a calling.', error.toString()],
@ -2918,6 +2930,7 @@ export class BaileysStartupService extends ChannelStartupService {
try { try {
return await this.client.sendMessage(del.remoteJid, { delete: del }); return await this.client.sendMessage(del.remoteJid, { delete: del });
} catch (error) { } catch (error) {
this.logger.error('line 2934');
throw new InternalServerErrorException('Error while deleting message for everyone', error?.toString()); throw new InternalServerErrorException('Error while deleting message for everyone', error?.toString());
} }
} }
@ -3009,6 +3022,7 @@ export class BaileysStartupService extends ChannelStartupService {
buffer: getBuffer ? buffer : null, buffer: getBuffer ? buffer : null,
}; };
} catch (error) { } catch (error) {
this.logger.error('line 3026');
this.logger.error(error); this.logger.error(error);
throw new BadRequestException(error.toString()); throw new BadRequestException(error.toString());
} }
@ -3050,6 +3064,7 @@ export class BaileysStartupService extends ChannelStartupService {
}, },
}; };
} catch (error) { } catch (error) {
this.logger.error('line 3068');
throw new InternalServerErrorException('Error updating privacy settings', error.toString()); throw new InternalServerErrorException('Error updating privacy settings', error.toString());
} }
} }
@ -3075,6 +3090,7 @@ export class BaileysStartupService extends ChannelStartupService {
...profile, ...profile,
}; };
} catch (error) { } catch (error) {
this.logger.error('line 3094');
throw new InternalServerErrorException('Error updating profile name', error.toString()); throw new InternalServerErrorException('Error updating profile name', error.toString());
} }
} }
@ -3085,6 +3101,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3105');
throw new InternalServerErrorException('Error updating profile name', error.toString()); throw new InternalServerErrorException('Error updating profile name', error.toString());
} }
} }
@ -3095,6 +3112,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3116');
throw new InternalServerErrorException('Error updating profile status', error.toString()); throw new InternalServerErrorException('Error updating profile status', error.toString());
} }
} }
@ -3136,6 +3154,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3158');
throw new InternalServerErrorException('Error updating profile picture', error.toString()); throw new InternalServerErrorException('Error updating profile picture', error.toString());
} }
} }
@ -3148,6 +3167,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3171');
throw new InternalServerErrorException('Error removing profile picture', error.toString()); throw new InternalServerErrorException('Error removing profile picture', error.toString());
} }
} }
@ -3168,6 +3188,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { block: 'success' }; return { block: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3192');
throw new InternalServerErrorException('Error blocking user', error.toString()); throw new InternalServerErrorException('Error blocking user', error.toString());
} }
} }
@ -3198,6 +3219,7 @@ export class BaileysStartupService extends ChannelStartupService {
return null; return null;
} catch (error) { } catch (error) {
this.logger.error('line 3223');
this.logger.error(error); this.logger.error(error);
throw new BadRequestException(error.toString()); throw new BadRequestException(error.toString());
} }
@ -3219,6 +3241,7 @@ export class BaileysStartupService extends ChannelStartupService {
edit: data.key, edit: data.key,
}); });
} catch (error) { } catch (error) {
this.logger.error('line 3245');
this.logger.error(error); this.logger.error(error);
throw new BadRequestException(error.toString()); throw new BadRequestException(error.toString());
} }
@ -3261,6 +3284,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { numberJid: contact.jid, labelId: data.labelId, remove: true }; return { numberJid: contact.jid, labelId: data.labelId, remove: true };
} }
} catch (error) { } catch (error) {
this.logger.error('line 3288');
throw new BadRequestException(`Unable to ${data.action} label to chat`, error.toString()); throw new BadRequestException(`Unable to ${data.action} label to chat`, error.toString());
} }
} }
@ -3270,14 +3294,19 @@ export class BaileysStartupService extends ChannelStartupService {
try { try {
const meta = await this.client.groupMetadata(groupJid); const meta = await this.client.groupMetadata(groupJid);
this.logger.verbose(`Updating cache for group: ${groupJid}`); const cacheConf = this.configService.get<CacheConf>('CACHE');
await groupMetadataCache.set(groupJid, {
timestamp: Date.now(), if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) {
data: meta, this.logger.verbose(`Updating cache for group: ${groupJid}`);
}); await groupMetadataCache.set(groupJid, {
timestamp: Date.now(),
data: meta,
});
}
return meta; return meta;
} catch (error) { } catch (error) {
this.logger.error('line 3310');
this.logger.error(error); this.logger.error(error);
return null; return null;
} }
@ -3286,19 +3315,25 @@ export class BaileysStartupService extends ChannelStartupService {
private async getGroupMetadataCache(groupJid: string) { private async getGroupMetadataCache(groupJid: string) {
if (!isJidGroup(groupJid)) return null; if (!isJidGroup(groupJid)) return null;
if (await groupMetadataCache.has(groupJid)) { const cacheConf = this.configService.get<CacheConf>('CACHE');
console.log(`Cache request for group: ${groupJid}`);
const meta = await groupMetadataCache.get(groupJid);
if (Date.now() - meta.timestamp > 3600000) { if ((cacheConf?.REDIS?.ENABLED && cacheConf?.REDIS?.URI !== '') || cacheConf?.LOCAL?.ENABLED) {
await this.updateGroupMetadataCache(groupJid); if (await groupMetadataCache.has(groupJid)) {
console.log(`Cache request for group: ${groupJid}`);
const meta = await groupMetadataCache.get(groupJid);
if (Date.now() - meta.timestamp > 3600000) {
await this.updateGroupMetadataCache(groupJid);
}
return meta.data;
} }
return meta.data; console.log(`Cache request for group: ${groupJid} - not found`);
return await this.updateGroupMetadataCache(groupJid);
} }
console.log(`Cache request for group: ${groupJid} - not found`); return await this.findGroup({ groupJid }, 'inner');
return await this.updateGroupMetadataCache(groupJid);
} }
public async createGroup(create: CreateGroupDto) { public async createGroup(create: CreateGroupDto) {
@ -3324,6 +3359,7 @@ export class BaileysStartupService extends ChannelStartupService {
return group; return group;
} catch (error) { } catch (error) {
this.logger.error('line 3363');
this.logger.error(error); this.logger.error(error);
throw new InternalServerErrorException('Error creating group', error.toString()); throw new InternalServerErrorException('Error creating group', error.toString());
} }
@ -3363,6 +3399,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3403');
throw new InternalServerErrorException('Error update group picture', error.toString()); throw new InternalServerErrorException('Error update group picture', error.toString());
} }
} }
@ -3373,6 +3410,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3414');
throw new InternalServerErrorException('Error updating group subject', error.toString()); throw new InternalServerErrorException('Error updating group subject', error.toString());
} }
} }
@ -3383,6 +3421,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { update: 'success' }; return { update: 'success' };
} catch (error) { } catch (error) {
this.logger.error('line 3425');
throw new InternalServerErrorException('Error updating group description', error.toString()); throw new InternalServerErrorException('Error updating group description', error.toString());
} }
} }
@ -3417,6 +3456,7 @@ export class BaileysStartupService extends ChannelStartupService {
if (reply === 'inner') { if (reply === 'inner') {
return; return;
} }
this.logger.error('line 3460');
throw new NotFoundException('Error fetching group', error.toString()); throw new NotFoundException('Error fetching group', error.toString());
} }
} }
@ -3426,8 +3466,7 @@ export class BaileysStartupService extends ChannelStartupService {
let groups = []; let groups = [];
for (const group of fetch) { for (const group of fetch) {
const picture = null; const picture = await this.profilePicture(group.id);
// const picture = await this.profilePicture(group.id);
const result = { const result = {
id: group.id, id: group.id,
@ -3459,6 +3498,7 @@ export class BaileysStartupService extends ChannelStartupService {
const code = await this.client.groupInviteCode(id.groupJid); const code = await this.client.groupInviteCode(id.groupJid);
return { inviteUrl: `https://chat.whatsapp.com/${code}`, inviteCode: code }; return { inviteUrl: `https://chat.whatsapp.com/${code}`, inviteCode: code };
} catch (error) { } catch (error) {
this.logger.error('line 3502');
throw new NotFoundException('No invite code', error.toString()); throw new NotFoundException('No invite code', error.toString());
} }
} }
@ -3467,6 +3507,7 @@ export class BaileysStartupService extends ChannelStartupService {
try { try {
return await this.client.groupGetInviteInfo(id.inviteCode); return await this.client.groupGetInviteInfo(id.inviteCode);
} catch (error) { } catch (error) {
this.logger.error('line 3511');
throw new NotFoundException('No invite info', id.inviteCode); throw new NotFoundException('No invite info', id.inviteCode);
} }
} }
@ -3492,6 +3533,7 @@ export class BaileysStartupService extends ChannelStartupService {
return { send: true, inviteUrl }; return { send: true, inviteUrl };
} catch (error) { } catch (error) {
this.logger.error('line 3537');
throw new NotFoundException('No send invite'); throw new NotFoundException('No send invite');
} }
} }
@ -3501,6 +3543,7 @@ export class BaileysStartupService extends ChannelStartupService {
const groupJid = await this.client.groupAcceptInvite(id.inviteCode); const groupJid = await this.client.groupAcceptInvite(id.inviteCode);
return { accepted: true, groupJid: groupJid }; return { accepted: true, groupJid: groupJid };
} catch (error) { } catch (error) {
this.logger.error('line 3547');
throw new NotFoundException('Accept invite error', error.toString()); throw new NotFoundException('Accept invite error', error.toString());
} }
} }
@ -3510,6 +3553,7 @@ export class BaileysStartupService extends ChannelStartupService {
const inviteCode = await this.client.groupRevokeInvite(id.groupJid); const inviteCode = await this.client.groupRevokeInvite(id.groupJid);
return { revoked: true, inviteCode }; return { revoked: true, inviteCode };
} catch (error) { } catch (error) {
this.logger.error('line 3557');
throw new NotFoundException('Revoke error', error.toString()); throw new NotFoundException('Revoke error', error.toString());
} }
} }
@ -3535,6 +3579,7 @@ export class BaileysStartupService extends ChannelStartupService {
}); });
return { participants: parsedParticipants }; return { participants: parsedParticipants };
} catch (error) { } catch (error) {
this.logger.error('line 3583');
throw new NotFoundException('No participants', error.toString()); throw new NotFoundException('No participants', error.toString());
} }
} }
@ -3549,6 +3594,7 @@ export class BaileysStartupService extends ChannelStartupService {
); );
return { updateParticipants: updateParticipants }; return { updateParticipants: updateParticipants };
} catch (error) { } catch (error) {
this.logger.error('line 3598');
throw new BadRequestException('Error updating participants', error.toString()); throw new BadRequestException('Error updating participants', error.toString());
} }
} }
@ -3558,6 +3604,7 @@ export class BaileysStartupService extends ChannelStartupService {
const updateSetting = await this.client.groupSettingUpdate(update.groupJid, update.action); const updateSetting = await this.client.groupSettingUpdate(update.groupJid, update.action);
return { updateSetting: updateSetting }; return { updateSetting: updateSetting };
} catch (error) { } catch (error) {
this.logger.error('line 3608');
throw new BadRequestException('Error updating setting', error.toString()); throw new BadRequestException('Error updating setting', error.toString());
} }
} }
@ -3567,6 +3614,7 @@ export class BaileysStartupService extends ChannelStartupService {
await this.client.groupToggleEphemeral(update.groupJid, update.expiration); await this.client.groupToggleEphemeral(update.groupJid, update.expiration);
return { success: true }; return { success: true };
} catch (error) { } catch (error) {
this.logger.error('line 3618');
throw new BadRequestException('Error updating setting', error.toString()); throw new BadRequestException('Error updating setting', error.toString());
} }
} }
@ -3576,6 +3624,7 @@ export class BaileysStartupService extends ChannelStartupService {
await this.client.groupLeave(id.groupJid); await this.client.groupLeave(id.groupJid);
return { groupJid: id.groupJid, leave: true }; return { groupJid: id.groupJid, leave: true };
} catch (error) { } catch (error) {
this.logger.error('line 3628');
throw new BadRequestException('Unable to leave the group', error.toString()); throw new BadRequestException('Unable to leave the group', error.toString());
} }
} }

View File

@ -121,7 +121,7 @@ export class WAMonitoringService {
public async cleaningUp(instanceName: string) { public async cleaningUp(instanceName: string) {
let instanceDbId: string; let instanceDbId: string;
if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { if (this.db.SAVE_DATA.INSTANCE) {
const instance = await this.prismaRepository.instance.update({ const instance = await this.prismaRepository.instance.update({
where: { name: instanceName }, where: { name: instanceName },
data: { connectionStatus: 'close' }, data: { connectionStatus: 'close' },
@ -181,7 +181,7 @@ export class WAMonitoringService {
try { try {
if (this.providerSession?.ENABLED) { if (this.providerSession?.ENABLED) {
await this.loadInstancesFromProvider(); await this.loadInstancesFromProvider();
} else if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { } else if (this.db.SAVE_DATA.INSTANCE) {
await this.loadInstancesFromDatabasePostgres(); await this.loadInstancesFromDatabasePostgres();
} else if (this.redis.REDIS.ENABLED && this.redis.REDIS.SAVE_INSTANCES) { } else if (this.redis.REDIS.ENABLED && this.redis.REDIS.SAVE_INSTANCES) {
await this.loadInstancesFromRedis(); await this.loadInstancesFromRedis();
@ -193,21 +193,19 @@ export class WAMonitoringService {
public async saveInstance(data: any) { public async saveInstance(data: any) {
try { try {
if (this.db.ENABLED) { const clientName = await this.configService.get<Database>('DATABASE').CONNECTION.CLIENT_NAME;
const clientName = await this.configService.get<Database>('DATABASE').CONNECTION.CLIENT_NAME; await this.prismaRepository.instance.create({
await this.prismaRepository.instance.create({ data: {
data: { id: data.instanceId,
id: data.instanceId, name: data.instanceName,
name: data.instanceName, connectionStatus: data.integration && data.integration === Integration.WHATSAPP_BUSINESS ? 'open' : 'close',
connectionStatus: data.integration && data.integration === Integration.WHATSAPP_BUSINESS ? 'open' : 'close', number: data.number,
number: data.number, integration: data.integration || Integration.WHATSAPP_BAILEYS,
integration: data.integration || Integration.WHATSAPP_BAILEYS, token: data.hash,
token: data.hash, clientName: clientName,
clientName: clientName, businessId: data.businessId,
businessId: data.businessId, },
}, });
});
}
} catch (error) { } catch (error) {
this.logger.error(error); this.logger.error(error);
} }

View File

@ -51,7 +51,6 @@ export type DBConnection = {
}; };
export type Database = { export type Database = {
CONNECTION: DBConnection; CONNECTION: DBConnection;
ENABLED: boolean;
PROVIDER: string; PROVIDER: string;
SAVE_DATA: SaveData; SAVE_DATA: SaveData;
}; };
@ -202,6 +201,7 @@ export type S3 = {
ENABLE: boolean; ENABLE: boolean;
PORT?: number; PORT?: number;
USE_SSL?: boolean; USE_SSL?: boolean;
REGION?: string;
}; };
export type CacheConf = { REDIS: CacheConfRedis; LOCAL: CacheConfLocal }; export type CacheConf = { REDIS: CacheConfRedis; LOCAL: CacheConfLocal };
@ -285,7 +285,6 @@ export class ConfigService {
URI: process.env.DATABASE_CONNECTION_URI || '', URI: process.env.DATABASE_CONNECTION_URI || '',
CLIENT_NAME: process.env.DATABASE_CONNECTION_CLIENT_NAME || 'evolution', CLIENT_NAME: process.env.DATABASE_CONNECTION_CLIENT_NAME || 'evolution',
}, },
ENABLED: process.env?.DATABASE_ENABLED === 'true',
PROVIDER: process.env.DATABASE_PROVIDER || 'postgresql', PROVIDER: process.env.DATABASE_PROVIDER || 'postgresql',
SAVE_DATA: { SAVE_DATA: {
INSTANCE: process.env?.DATABASE_SAVE_DATA_INSTANCE === 'true', INSTANCE: process.env?.DATABASE_SAVE_DATA_INSTANCE === 'true',
@ -464,6 +463,7 @@ export class ConfigService {
ENABLE: process.env?.S3_ENABLED === 'true', ENABLE: process.env?.S3_ENABLED === 'true',
PORT: Number.parseInt(process.env?.S3_PORT || '9000'), PORT: Number.parseInt(process.env?.S3_PORT || '9000'),
USE_SSL: process.env?.S3_USE_SSL === 'true', USE_SSL: process.env?.S3_USE_SSL === 'true',
REGION: process.env?.S3_REGION,
}, },
AUTHENTICATION: { AUTHENTICATION: {
API_KEY: { API_KEY: {

View File

@ -1,21 +1,16 @@
import { configService, Database } from '@config/env.config';
import { Logger } from '@config/logger.config'; import { Logger } from '@config/logger.config';
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
const logger = new Logger('Prisma'); const logger = new Logger('Prisma');
const db = configService.get<Database>('DATABASE');
export const prismaServer = (() => { export const prismaServer = (() => {
if (db.ENABLED) { logger.verbose('connecting');
logger.verbose('connecting'); const db = new PrismaClient();
const db = new PrismaClient();
process.on('beforeExit', () => { process.on('beforeExit', () => {
logger.verbose('instance destroyed'); logger.verbose('instance destroyed');
db.$disconnect(); db.$disconnect();
}); });
return db; return db;
}
})(); })();

View File

@ -1,5 +1,3 @@
import 'express-async-errors';
import { initAMQP, initGlobalQueues } from '@api/integrations/rabbitmq/libs/amqp.server'; import { initAMQP, initGlobalQueues } from '@api/integrations/rabbitmq/libs/amqp.server';
import { initSQS } from '@api/integrations/sqs/libs/sqs.server'; import { initSQS } from '@api/integrations/sqs/libs/sqs.server';
import { ProviderFiles } from '@api/provider/sessions'; import { ProviderFiles } from '@api/provider/sessions';
@ -10,6 +8,7 @@ import { Auth, configService, Cors, HttpServer, ProviderSession, Rabbitmq, Sqs,
import { onUnexpectedError } from '@config/error.config'; import { onUnexpectedError } from '@config/error.config';
import { Logger } from '@config/logger.config'; import { Logger } from '@config/logger.config';
import { ROOT_DIR } from '@config/path.config'; import { ROOT_DIR } from '@config/path.config';
import * as Sentry from '@sentry/node';
import { ServerUP } from '@utils/server-up'; import { ServerUP } from '@utils/server-up';
import axios from 'axios'; import axios from 'axios';
import compression from 'compression'; import compression from 'compression';
@ -24,6 +23,19 @@ function initWA() {
async function bootstrap() { async function bootstrap() {
const logger = new Logger('SERVER'); const logger = new Logger('SERVER');
const app = express(); const app = express();
const dsn = process.env.SENTRY_DSN;
if (dsn) {
logger.info('Sentry - ON');
Sentry.init({
dsn: dsn,
environment: process.env.NODE_ENV || 'development',
tracesSampleRate: 1.0,
});
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.tracingHandler());
app.use(Sentry.Handlers.errorHandler());
}
let providerFiles: ProviderFiles = null; let providerFiles: ProviderFiles = null;
if (configService.get<ProviderSession>('PROVIDER').ENABLED) { if (configService.get<ProviderSession>('PROVIDER').ENABLED) {

View File

@ -1,3 +1,5 @@
import { cpSync } from 'node:fs';
import { defineConfig } from 'tsup'; import { defineConfig } from 'tsup';
export default defineConfig({ export default defineConfig({
@ -8,4 +10,10 @@ export default defineConfig({
clean: true, clean: true,
minify: true, minify: true,
format: ['cjs', 'esm'], format: ['cjs', 'esm'],
onSuccess: async () => {
cpSync('src/utils/translations', 'dist/translations', { recursive: true });
},
loader: {
'.json': 'file',
},
}); });