chore: Update 'baileys' dependency to use 'EvolutionAPI' repository

The 'baileys' dependency in the 'package.json' file has been updated to use the 'EvolutionAPI' repository instead of 'WhiskeySockets'. This change ensures that the latest version of 'baileys' is used, which includes improvements in group message sending and cache utilization.

Modified files:
- package.json
This commit is contained in:
Davidson Gomes 2024-06-27 17:49:48 -03:00
parent 228dcf8aa5
commit b5683aed2a
4 changed files with 188 additions and 278 deletions

View File

@ -18,6 +18,7 @@
* Now in typebot we wait until the terminal block to accept the user's message, if it arrives before the block is sent, it is ignored * Now in typebot we wait until the terminal block to accept the user's message, if it arrives before the block is sent, it is ignored
* Correction of audio sending, now we can speed it up and have the audio wireframe * Correction of audio sending, now we can speed it up and have the audio wireframe
* Reply with media message on Chatwoot * Reply with media message on Chatwoot
* improvements in sending status and groups
### Break changes ### Break changes

View File

@ -54,7 +54,7 @@
"@sentry/node": "^7.59.2", "@sentry/node": "^7.59.2",
"amqplib": "^0.10.3", "amqplib": "^0.10.3",
"axios": "^1.6.5", "axios": "^1.6.5",
"baileys": "github:WhiskeySockets/Baileys", "baileys": "github:EvolutionAPI/Baileys",
"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

@ -22,6 +22,7 @@ import makeWASocket, {
GroupParticipant, GroupParticipant,
isJidBroadcast, isJidBroadcast,
isJidGroup, isJidGroup,
isJidNewsletter,
isJidUser, isJidUser,
makeCacheableSignalKeyStore, makeCacheableSignalKeyStore,
MessageUpsertType, MessageUpsertType,
@ -506,10 +507,149 @@ export class BaileysStartupService extends ChannelStartupService {
} }
if (db.SAVE_DATA.INSTANCE && db.ENABLED) { if (db.SAVE_DATA.INSTANCE && db.ENABLED) {
return await useMultiFileAuthStatePrisma(this.instance.id); return await useMultiFileAuthStatePrisma(this.instance.id, this.cache);
} }
} }
private async createClient(number?: string): Promise<WASocket> {
this.instance.authState = await this.defineAuthState();
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
let browserOptions = {};
if (number || this.phoneNumber) {
this.phoneNumber = number;
this.logger.info(`Phone number: ${number}`);
} else {
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
browserOptions = { browser };
this.logger.info(`Browser: ${browser}`);
}
let version;
let log;
if (session.VERSION) {
version = session.VERSION.split('.');
log = `Baileys version env: ${version}`;
} else {
const baileysVersion = await fetchLatestBaileysVersion();
version = baileysVersion.version;
log = `Baileys version: ${version}`;
}
this.logger.info(log);
this.logger.info(`Group Ignore: ${this.localSettings.groupsIgnore}`);
let options;
if (this.localProxy.enabled) {
this.logger.info('Proxy enabled: ' + this.localProxy?.host);
if (this.localProxy?.host?.includes('proxyscrape')) {
try {
const response = await axios.get(this.localProxy?.host);
const text = response.data;
const proxyUrls = text.split('\r\n');
const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length));
const proxyUrl = 'http://' + proxyUrls[rand];
options = {
agent: makeProxyAgent(proxyUrl),
fetchAgent: makeProxyAgent(proxyUrl),
};
} catch (error) {
this.localProxy.enabled = false;
}
} else {
options = {
agent: makeProxyAgent({
host: this.localProxy.host,
port: this.localProxy.port,
protocol: this.localProxy.protocol,
username: this.localProxy.username,
password: this.localProxy.password,
}),
fetchAgent: makeProxyAgent({
host: this.localProxy.host,
port: this.localProxy.port,
protocol: this.localProxy.protocol,
username: this.localProxy.username,
password: this.localProxy.password,
}),
};
}
}
const socketConfig: UserFacingSocketConfig = {
...options,
auth: {
creds: this.instance.authState.state.creds,
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any),
},
logger: P({ level: this.logBaileys }),
printQRInTerminal: false,
...browserOptions,
version,
markOnlineOnConnect: this.localSettings.alwaysOnline,
retryRequestDelayMs: 350,
maxMsgRetryCount: 4,
fireInitQueries: true,
connectTimeoutMs: 20_000,
keepAliveIntervalMs: 30_000,
qrTimeout: 45_000,
defaultQueryTimeoutMs: undefined,
emitOwnEvents: false,
shouldIgnoreJid: (jid) => {
const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid);
const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid);
const isNewsletter = isJidNewsletter(jid);
return isGroupJid || isBroadcast || isNewsletter;
},
msgRetryCounterCache: this.msgRetryCounterCache,
getMessage: async (key) => (await this.getMessage(key)) as Promise<proto.IMessage>,
generateHighQualityLinkPreview: true,
syncFullHistory: this.localSettings.syncFullHistory,
shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => {
return this.historySyncNotification(msg);
},
userDevicesCache: this.userDevicesCache,
transactionOpts: { maxCommitRetries: 5, delayBetweenTriesMs: 2500 },
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.client = makeWASocket(socketConfig);
this.eventHandler();
this.phoneNumber = number;
return this.client;
}
public async connectToWhatsapp(number?: string): Promise<WASocket> { public async connectToWhatsapp(number?: string): Promise<WASocket> {
try { try {
this.loadWebhook(); this.loadWebhook();
@ -520,142 +660,7 @@ export class BaileysStartupService extends ChannelStartupService {
this.loadSqs(); this.loadSqs();
this.loadProxy(); this.loadProxy();
this.instance.authState = await this.defineAuthState(); return await this.createClient(number);
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
let browserOptions = {};
if (number || this.phoneNumber) {
this.phoneNumber = number;
this.logger.info(`Phone number: ${number}`);
} else {
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
browserOptions = { browser };
this.logger.info(`Browser: ${browser}`);
}
let version;
let log;
if (session.VERSION) {
version = session.VERSION.split('.');
log = `Baileys version env: ${version}`;
} else {
const baileysVersion = await fetchLatestBaileysVersion();
version = baileysVersion.version;
log = `Baileys version: ${version}`;
}
this.logger.info(log);
this.logger.info(`Group Ignore: ${this.localSettings.groupsIgnore}`);
let options;
if (this.localProxy.enabled) {
this.logger.info('Proxy enabled: ' + this.localProxy?.host);
if (this.localProxy?.host?.includes('proxyscrape')) {
try {
const response = await axios.get(this.localProxy?.host);
const text = response.data;
const proxyUrls = text.split('\r\n');
const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length));
const proxyUrl = 'http://' + proxyUrls[rand];
options = {
agent: makeProxyAgent(proxyUrl),
fetchAgent: makeProxyAgent(proxyUrl),
};
} catch (error) {
this.localProxy.enabled = false;
}
} else {
options = {
agent: makeProxyAgent({
host: this.localProxy.host,
port: this.localProxy.port,
protocol: this.localProxy.protocol,
username: this.localProxy.username,
password: this.localProxy.password,
}),
fetchAgent: makeProxyAgent({
host: this.localProxy.host,
port: this.localProxy.port,
protocol: this.localProxy.protocol,
username: this.localProxy.username,
password: this.localProxy.password,
}),
};
}
}
const socketConfig: UserFacingSocketConfig = {
...options,
auth: {
creds: this.instance.authState.state.creds,
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any),
},
logger: P({ level: this.logBaileys }),
printQRInTerminal: false,
...browserOptions,
version,
markOnlineOnConnect: this.localSettings.alwaysOnline,
retryRequestDelayMs: 350,
maxMsgRetryCount: 4,
fireInitQueries: true,
connectTimeoutMs: 20_000,
keepAliveIntervalMs: 30_000,
qrTimeout: 45_000,
defaultQueryTimeoutMs: undefined,
emitOwnEvents: false,
shouldIgnoreJid: (jid) => {
const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid);
const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid);
const isNewsletter = jid.includes('newsletter');
return isGroupJid || isBroadcast || isNewsletter;
},
msgRetryCounterCache: this.msgRetryCounterCache,
getMessage: async (key) => (await this.getMessage(key)) as Promise<proto.IMessage>,
generateHighQualityLinkPreview: true,
syncFullHistory: this.localSettings.syncFullHistory,
shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => {
return this.historySyncNotification(msg);
},
userDevicesCache: this.userDevicesCache,
transactionOpts: { maxCommitRetries: 5, delayBetweenTriesMs: 2500 },
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;
},
};
this.endSession = false;
this.client = makeWASocket(socketConfig);
this.eventHandler();
this.phoneNumber = number;
return this.client;
} catch (error) { } catch (error) {
this.logger.error(error); this.logger.error(error);
throw new InternalServerErrorException(error?.toString()); throw new InternalServerErrorException(error?.toString());
@ -664,132 +669,7 @@ export class BaileysStartupService extends ChannelStartupService {
public async reloadConnection(): Promise<WASocket> { public async reloadConnection(): Promise<WASocket> {
try { try {
this.instance.authState = await this.defineAuthState(); return await this.createClient(this.phoneNumber);
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
let browserOptions = {};
if (this.phoneNumber) {
this.logger.info(`Phone number: ${this.phoneNumber}`);
} else {
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
browserOptions = { browser };
this.logger.info(`Browser: ${browser}`);
}
let version;
let log;
if (session.VERSION) {
version = session.VERSION.split('.');
log = `Baileys version env: ${version}`;
} else {
const baileysVersion = await fetchLatestBaileysVersion();
version = baileysVersion.version;
log = `Baileys version: ${version}`;
}
this.logger.info(log);
let options;
if (this.localProxy.enabled) {
this.logger.info('Proxy enabled: ' + this.localProxy?.host);
if (this.localProxy?.host?.includes('proxyscrape')) {
try {
const response = await axios.get(this.localProxy?.host);
const text = response.data;
const proxyUrls = text.split('\r\n');
const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length));
const proxyUrl = 'http://' + proxyUrls[rand];
options = {
agent: makeProxyAgent(proxyUrl),
fetchAgent: makeProxyAgent(proxyUrl),
};
} catch (error) {
this.localProxy.enabled = false;
}
} else {
options = {
agent: makeProxyAgent({
host: this.localProxy.host,
port: this.localProxy.port,
protocol: this.localProxy.protocol,
username: this.localProxy.username,
password: this.localProxy.password,
}),
fetchAgent: makeProxyAgent({
host: this.localProxy.host,
port: this.localProxy.port,
protocol: this.localProxy.protocol,
username: this.localProxy.username,
password: this.localProxy.password,
}),
};
}
}
const socketConfig: UserFacingSocketConfig = {
...options,
auth: {
creds: this.instance.authState.state.creds,
keys: makeCacheableSignalKeyStore(this.instance.authState.state.keys, P({ level: 'error' }) as any),
},
logger: P({ level: this.logBaileys }),
printQRInTerminal: false,
...browserOptions,
version,
markOnlineOnConnect: this.localSettings.alwaysOnline,
retryRequestDelayMs: 350,
maxMsgRetryCount: 4,
fireInitQueries: true,
connectTimeoutMs: 20_000,
keepAliveIntervalMs: 30_000,
qrTimeout: 45_000,
defaultQueryTimeoutMs: undefined,
emitOwnEvents: false,
shouldIgnoreJid: (jid) => {
const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid);
const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid);
const isNewsletter = jid.includes('newsletter');
return isGroupJid || isBroadcast || isNewsletter;
},
msgRetryCounterCache: this.msgRetryCounterCache,
getMessage: async (key) => (await this.getMessage(key)) as Promise<proto.IMessage>,
generateHighQualityLinkPreview: true,
syncFullHistory: this.localSettings.syncFullHistory,
shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => {
return this.historySyncNotification(msg);
},
userDevicesCache: this.userDevicesCache,
transactionOpts: { maxCommitRetries: 5, delayBetweenTriesMs: 2500 },
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;
},
};
this.client = makeWASocket(socketConfig);
return this.client;
} catch (error) { } catch (error) {
this.logger.error(error); this.logger.error(error);
throw new InternalServerErrorException(error?.toString()); throw new InternalServerErrorException(error?.toString());
@ -1747,11 +1627,13 @@ export class BaileysStartupService extends ChannelStartupService {
quoted, quoted,
}; };
if (participants) if (isJidGroup(sender)) {
option.cachedGroupMetadata = async () => { if (participants)
return { participants: participants as GroupParticipant[] }; option.cachedGroupMetadata = async () => {
}; return { participants: participants as GroupParticipant[] };
else option.cachedGroupMetadata = this.getGroupMetadataCache; };
else option.cachedGroupMetadata = this.getGroupMetadataCache;
}
if (ephemeralExpiration) option.ephemeralExpiration = ephemeralExpiration; if (ephemeralExpiration) option.ephemeralExpiration = ephemeralExpiration;
@ -1968,7 +1850,6 @@ export class BaileysStartupService extends ChannelStartupService {
return jid; return jid;
}); });
} }
// console.log('group.participants', group.participants.length); // console.log('group.participants', group.participants.length);
// const batchSize = 200; // const batchSize = 200;
@ -1985,7 +1866,16 @@ export class BaileysStartupService extends ChannelStartupService {
// let msgId: string | null = null; // let msgId: string | null = null;
// if (firstBatch) { // if (firstBatch) {
// firstMessage = await this.sendMessage(sender, message, mentions, linkPreview, quoted, null, firstBatch); // firstMessage = await this.sendMessage(
// sender,
// message,
// mentions,
// linkPreview,
// quoted,
// null,
// group?.ephemeralDuration,
// firstBatch,
// );
// msgId = firstMessage.key.id; // msgId = firstMessage.key.id;
// } // }
@ -1994,12 +1884,23 @@ export class BaileysStartupService extends ChannelStartupService {
// await Promise.allSettled( // await Promise.allSettled(
// batches.map(async (batch: GroupParticipant[]) => { // batches.map(async (batch: GroupParticipant[]) => {
// const messageSent = await this.sendMessage(sender, message, mentions, linkPreview, quoted, msgId, batch); // const messageSent = await this.sendMessage(
// sender,
// message,
// mentions,
// linkPreview,
// quoted,
// msgId,
// group?.ephemeralDuration,
// batch,
// );
// return messageSent; // return messageSent;
// }), // }),
// ); // );
// messageSent = firstMessage;
messageSent = await this.sendMessage( messageSent = await this.sendMessage(
sender, sender,
message, message,
@ -2008,6 +1909,7 @@ export class BaileysStartupService extends ChannelStartupService {
quoted, quoted,
null, null,
group?.ephemeralDuration, group?.ephemeralDuration,
group.participants,
); );
} else { } else {
messageSent = await this.sendMessage(sender, message, mentions, linkPreview, quoted); messageSent = await this.sendMessage(sender, message, mentions, linkPreview, quoted);

View File

@ -2,6 +2,7 @@ import { AuthenticationState, BufferJSON, initAuthCreds, WAProto as proto } from
import fs from 'fs/promises'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
import { CacheService } from '../api/services/cache.service';
import { INSTANCE_DIR } from '../config/path.config'; import { INSTANCE_DIR } from '../config/path.config';
import { prismaServer } from '../libs/prisma.connect'; import { prismaServer } from '../libs/prisma.connect';
@ -77,7 +78,10 @@ async function fileExists(file: string): Promise<any> {
} }
} }
export default async function useMultiFileAuthStatePrisma(sessionId: string): Promise<{ export default async function useMultiFileAuthStatePrisma(
sessionId: string,
cache: CacheService,
): Promise<{
state: AuthenticationState; state: AuthenticationState;
saveCreds: () => Promise<void>; saveCreds: () => Promise<void>;
}> { }> {
@ -89,8 +93,9 @@ export default async function useMultiFileAuthStatePrisma(sessionId: string): Pr
const dataString = JSON.stringify(data, BufferJSON.replacer); const dataString = JSON.stringify(data, BufferJSON.replacer);
if (key != 'creds') { if (key != 'creds') {
await fs.writeFile(localFile(key), dataString); return await cache.hSet(sessionId, key, data);
return; // await fs.writeFile(localFile(key), dataString);
// return;
} }
await saveKey(sessionId, dataString); await saveKey(sessionId, dataString);
return; return;
@ -101,8 +106,9 @@ export default async function useMultiFileAuthStatePrisma(sessionId: string): Pr
let rawData; let rawData;
if (key != 'creds') { if (key != 'creds') {
if (!(await fileExists(localFile(key)))) return null; return await cache.hGet(sessionId, key);
rawData = await fs.readFile(localFile(key), { encoding: 'utf-8' }); // if (!(await fileExists(localFile(key)))) return null;
// rawData = await fs.readFile(localFile(key), { encoding: 'utf-8' });
} else { } else {
rawData = await getAuthKey(sessionId); rawData = await getAuthKey(sessionId);
} }
@ -117,7 +123,8 @@ export default async function useMultiFileAuthStatePrisma(sessionId: string): Pr
async function removeData(key: string): Promise<any> { async function removeData(key: string): Promise<any> {
try { try {
if (key != 'creds') { if (key != 'creds') {
await fs.unlink(localFile(key)); return await cache.hDelete(sessionId, key);
// await fs.unlink(localFile(key));
} else { } else {
await deleteAuthKey(sessionId); await deleteAuthKey(sessionId);
} }