@areumtecnologia/baileys 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,456 @@
1
+ // Biblioteca chamada synapse-b
2
+ const wb = require('@whiskeysockets/baileys');
3
+ const {
4
+ Browsers,
5
+ makeWASocket,
6
+ decryptPollVote,
7
+ DisconnectReason,
8
+ jidNormalizedUser,
9
+ downloadContentFromMessage,
10
+ useMultiFileAuthState,
11
+ fetchLatestBaileysVersion,
12
+ } = require('@itsukichan/baileys');
13
+ const { Boom } = require('@hapi/boom');
14
+ const EventEmitter = require('events');
15
+ const fs = require('fs/promises');
16
+ const { constants } = require('fs');
17
+ const path = require('path');
18
+ const pino = require('pino');
19
+ // Importa os handlers de responsabilidades específicas
20
+ const MessageHandler = require('./handlers/messages');
21
+ const GroupHandler = require('./handlers/groups');
22
+ const { UserHandler, PresenceStatus } = require('./handlers/users');
23
+ const { MessageNormalizer, MessageStore } = require('./utils');
24
+ const { InteractiveMessage, CallButton, CopyCodeButton, ListButton, ListRow, ListSection, QuickReplyButton, UrlButton, LocationButton } = require('./types/interactive-messages');
25
+ const NodeCache = require("node-cache");
26
+ const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false });
27
+
28
+ /**
29
+ * Representa um wrapper de alto nível para a biblioteca Baileys, simplificando a criação e o gerenciamento de um cliente de WhatsApp.
30
+ * A classe abstrai a complexidade do ciclo de vida da conexão e emite eventos semânticos para todas as interações importantes.
31
+ *
32
+ * @extends {EventEmitter}
33
+ *
34
+ * @fires Client#status
35
+ * @fires Client#error
36
+ * @fires Client#message_received
37
+ * @fires Client#message_sent
38
+ * @fires Client#message_update
39
+ * @fires Client#message_delete
40
+ * @fires Client#message_reaction
41
+ * @fires Client#incoming_call
42
+ * @fires Client#group_update
43
+ * @fires Client#group_participants_update
44
+ * @fires Client#presence_update
45
+ * @fires Client#chat_update
46
+ * @fires Client#chat_delete
47
+ * @fires Client#contact_update
48
+ * @fires Client#blocklist_update
49
+ */
50
+ class Client extends EventEmitter {
51
+ /**
52
+ * Cria uma instância do Cliente.
53
+ * @param {object} [options={}] - Opções de configuração para o cliente.
54
+ * @param {string} [options.sessionName='session'] - O nome da sessão a ser usada, que nomeia a pasta de autenticação.
55
+ */
56
+ constructor(options = {}) {
57
+ super();
58
+ this.sock = null;
59
+ this.dataPath = options.dataPath || ".synapse-b/auth_data";
60
+ this.sessionName = options.sessionName;
61
+ this.authPath = [this.dataPath, this.sessionName].join('/');
62
+ this.store = options.store ? options.store : new MessageStore(this.authPath);
63
+ this.isOnline = false;
64
+ this.connected = false;
65
+ this.manualDisconnect = false;
66
+ this.receivedPendingNotifications = false;
67
+ this.loggerLevel = options.loggerLevel || "error";
68
+ this.restartOnClose = options.restartOnClose || false;
69
+ this.status = ClientEvent.DISCONNECTED;
70
+ this.markOnlineOnConnect = options.markOnlineOnConnect || false;
71
+ this.enviroment = options.enviroment ? options.enviroment : null;
72
+ this.qrCode = null;
73
+ // =================================================================================================
74
+ // INTEGRAÇÃO DOS HANDLERS
75
+ // =================================================================================================
76
+ // Instancia os handlers, passando a si mesma (this) como referência.
77
+ // Isso permite que os handlers acessem o 'sock' e outros métodos do cliente.
78
+ this.messages = new MessageHandler(this);
79
+ this.groups = new GroupHandler(this);
80
+ this.users = new UserHandler(this);
81
+ }
82
+
83
+ /**
84
+ * Inicia o cliente, configura a autenticação e estabelece a conexão com o WhatsApp.
85
+ * Gerencia todo o ciclo de vida da conexão, incluindo reconexão automática e solicitação de novo QR code.
86
+ * @returns {Promise<void>}
87
+ */
88
+ async connect() {
89
+ this.status = ClientEvent.INIT;
90
+ const { state, saveCreds } = await useMultiFileAuthState(this.authPath);
91
+ const { version } = await fetchLatestBaileysVersion();
92
+ const credsPath = path.resolve(process.cwd(), this.authPath, "creds.json");
93
+ const creds = await this.fileExists(credsPath);
94
+ if (creds) {
95
+ // Conecta usando @itsukichan/baileys
96
+ this.sock = makeWASocket({
97
+ auth: state,
98
+ version,
99
+ browser: this.enviroment ? this.enviroment : Browsers.macOS("Desktop"),
100
+ printQRInTerminal: false, // Desabilitamos para controlar via evento
101
+ logger: pino({ level: this.loggerLevel }),
102
+ markOnlineOnConnect: this.markOnlineOnConnect || false,
103
+ keepAliveIntervalMs: 15000,
104
+ cachedGroupMetadata: async (jid) => groupCache.get(jid),
105
+ getMessage: async (key) => {
106
+ const chatId = key.remoteJid;
107
+ const msg = this.store?.getMessage(chatId, key.id);
108
+ // precisa retornar o raw.message
109
+ return msg ? msg.raw?.message : undefined;
110
+ }
111
+ });
112
+ } else {
113
+ // Conecta usando Baileys
114
+ this.sock = wb.makeWASocket({
115
+ auth: state,
116
+ version,
117
+ browser: this.enviroment ? this.enviroment : Browsers.macOS("Desktop"),
118
+ printQRInTerminal: false, // Desabilitamos para controlar via evento
119
+ logger: pino({ level: this.loggerLevel }),
120
+ markOnlineOnConnect: this.markOnlineOnConnect || false,
121
+ cachedGroupMetadata: async (jid) => groupCache.get(jid),
122
+ getMessage: async (key) => {
123
+ const chatId = key.remoteJid;
124
+ const msg = this.store?.getMessage(chatId, key.id);
125
+ // precisa retornar o raw.message
126
+ return msg ? msg.raw?.message : undefined;
127
+ }
128
+ });
129
+ }
130
+
131
+ // =================================================================================================
132
+ // EVENTO CENTRALIZADO DE CICLO DE VIDA
133
+ // =================================================================================================
134
+
135
+ /**
136
+ * Disparado quando as credenciais são atualizadas.
137
+ * O handler `saveCreds` da Baileys cuida de persistir essas credenciais.
138
+ */
139
+ this.sock.ev.on('creds.update', saveCreds);
140
+
141
+ /**
142
+ * Gerencia TODAS as atualizações do estado da conexão, emitindo um evento 'status' padronizado.
143
+ */
144
+ this.sock.ev.on('connection.update', async (update) => {
145
+
146
+ const { connection, isOnline, receivedPendingNotifications, lastDisconnect, qr, isNewLogin } = update;
147
+
148
+ if (receivedPendingNotifications)
149
+ this.receivedPendingNotifications = true;
150
+
151
+ if (isOnline)
152
+ this.isOnline = true;
153
+
154
+ if (qr) {
155
+ this.qrCode = qr;
156
+ this.status = ClientEvent.PAIRING_CODE;
157
+ this.emit(ClientEvent.PAIRING_CODE, update);
158
+ this.emit(ClientEvent.STATUS_CHANGE, this.status);
159
+ return;
160
+ }
161
+
162
+ // intercepta a configuração de pairing e reinicio de conexao apos login bem sucedido...
163
+ if (isNewLogin && qr == undefined) {
164
+ this.qrCode = null;
165
+ this.status = ClientEvent.PAIRING_SUCCESS;
166
+ this.emit(ClientEvent.PAIRING_SUCCESS, update);
167
+ this.emit(ClientEvent.STATUS_CHANGE, this.status);
168
+ return;
169
+ }
170
+
171
+ // Dentro de 'connection.update'
172
+ switch (connection) {
173
+ case 'connecting':
174
+ this.status = ClientEvent.CONNECTING;
175
+ this.emit(ClientEvent.CONNECTING, update);
176
+ this.emit(ClientEvent.STATUS_CHANGE, this.status);
177
+ break;
178
+
179
+ case 'open':
180
+ this.connected = true;
181
+ this.manualDisconnect = false;
182
+ this.status = ClientEvent.CONNECTED;
183
+ this.emit(ClientEvent.CONNECTED, update);
184
+ this.emit(ClientEvent.STATUS_CHANGE, this.status);
185
+ this.presenceSetInterval = setInterval(() => {
186
+ if (this.sock?.sendPresenceUpdate) {
187
+ this.sock.sendPresenceUpdate('available').catch(() => { });
188
+ }
189
+ }, 30_000);
190
+ break;
191
+
192
+ case 'close':
193
+ // Cancelar o intervalo
194
+ if (this.presenceSetInterval) {
195
+ clearInterval(this.presenceSetInterval);
196
+ this.presenceSetInterval = null;
197
+ }
198
+ // Aqui entraria a lógica que já existe para tratar a desconexão
199
+ this.qrCode = null;
200
+ this.connected = false;
201
+ let disconnectReason, statusType;
202
+ const boomError = new Boom(lastDisconnect?.error);
203
+ const statusCode = boomError?.output?.statusCode;
204
+ const reasonType = boomError.data?.content?.[0]?.attrs?.type || boomError.data?.attrs?.type || 'unknown';
205
+
206
+ // Conexao fechada apos leitura bem-sucedida do qrcode para que uma nova conexao seja feita. Nao ha necessidade de disparar evento de desconexao
207
+ if (statusCode === DisconnectReason.restartRequired) {
208
+ return this.connect();
209
+ }
210
+
211
+ if (this.manualDisconnect) {
212
+ // Desconexão manual solicitada pelo cliente.
213
+ statusType = DisconnectReasons.MANUAL_DISCONNECT;
214
+ disconnectReason = { statusCode, statusType, reason: reasonType, details: lastDisconnect };
215
+ } else if (statusCode === DisconnectReason.loggedOut) {
216
+ // 'Sessão deslogada por motivo desconhecido.'
217
+ statusType = DisconnectReasons.LOGGED_OUT;
218
+ disconnectReason = { statusCode, statusType, reason: reasonType, details: boomError.data };
219
+ try {
220
+ await fs.rm(this.authPath, { recursive: true, force: true });
221
+ // if (this.restartOnClose) this.connect();
222
+ } catch (err) {
223
+ this.emit(ClientEvent.ERROR, err);
224
+ }
225
+ } else if (statusCode === 408) {
226
+ // 'Sessão deslogada por motivo desconhecido.'
227
+ statusType = DisconnectReasons.PAIRING_FAILED;
228
+ disconnectReason = { statusCode, statusType, reason: 'qr_read_attempts_ended', details: boomError.data };
229
+ } else {
230
+ //'Conexão perdida por erro ou instabilidade.'
231
+ statusType = DisconnectReasons.CONNECTION_ERROR;
232
+ disconnectReason = { statusCode, statusType, reason: reasonType, details: lastDisconnect?.error };
233
+ }
234
+
235
+ this.status = ClientEvent.DISCONNECTED;
236
+ this.emit(ClientEvent.DISCONNECTED, disconnectReason);
237
+ this.emit(ClientEvent.STATUS_CHANGE, this.status);
238
+ // Reinicia a conexao se o servidor originar desconexao, especialmente 503
239
+ if (statusCode === DisconnectReason.unavailableService) {
240
+ return this.connect();
241
+ }
242
+
243
+ // Lógica de reconexão em caso de erros desconhecidos
244
+ if (statusType === DisconnectReasons.CONNECTION_ERROR) {
245
+ this.emit(ClientEvent.ERROR, update);
246
+ if (this.restartOnClose) {
247
+ this.connect();
248
+ }
249
+ }
250
+ break;
251
+ }
252
+
253
+ });
254
+
255
+ // =================================================================================================
256
+ // OUTROS EVENTOS DE INTERAÇÃO
257
+ // =================================================================================================
258
+
259
+ this.sock.ev.on('call', (calls) => this.emit(ClientEvent.CALL, calls[0]));
260
+ this.sock.ev.on('groups.update', async ([event]) => {
261
+ this.emit(ClientEvent.GROUP_UPDATE, event);
262
+ const metadata = await this.sock.groupMetadata(event.id);
263
+ groupCache.set(event.id, metadata);
264
+ });
265
+
266
+ this.sock.ev.on('group-participants.update', async (event) => {
267
+ this.emit(ClientEvent.GROUP_PARTICIPANTS_UPDATE, event);
268
+ const metadata = await this.sock.groupMetadata(event.id)
269
+ groupCache.set(event.id, metadata)
270
+ });
271
+ // this.sock.ev.on('groups.update', (updates) => this.emit(ClientEvent.GROUP_UPDATE, updates));
272
+ // this.sock.ev.on('group-participants.update', (update) => this.emit(ClientEvent.GROUP_PARTICIPANTS_UPDATE, update));
273
+ this.sock.ev.on('presence.update', (update) => this.emit(ClientEvent.PRESENCE_UPDATE, update));
274
+ this.sock.ev.on('contacts.update', (updates) => this.emit(ClientEvent.CONTACT_UPDATE, updates));
275
+ this.sock.ev.on('blocklist.update', (update) => this.emit(ClientEvent.BLOCKLIST_UPDATE, update));
276
+ this.sock.ev.on('chats.update', (updates) => this.emit(ClientEvent.CHAT_UPDATE, updates));
277
+ this.sock.ev.on('chats.delete', (jids) => this.emit(ClientEvent.CHAT_DELETE, jids));
278
+
279
+ this.sock.ev.on('messaging-history.set', (history) => {
280
+ try {
281
+
282
+ for (const chat of history.chats) {
283
+ const chatId = chat.id;
284
+ const messages = history.messages.filter(m => m.key.remoteJid === chatId);
285
+ for (const msg of messages) {
286
+ const nmsg = MessageNormalizer.normalize(msg, this);
287
+ if (nmsg && this.store && this.store.setMessage) this.store.setMessage(chatId, nmsg);
288
+ }
289
+ }
290
+ this.emit(ClientEvent.MESSAGES_HISTORY_SYNC_DONE, history);
291
+
292
+ } catch (error) {
293
+ this.emit(ClientEvent.ERROR, error);
294
+ }
295
+ });
296
+ this.sock.ev.on('messages.update', (updates) => this.emit(ClientEvent.MESSAGE_UPDATE, updates));
297
+ this.sock.ev.on('messages.delete', (item) => this.emit(ClientEvent.MESSAGE_DELETE, item));
298
+ this.sock.ev.on('messages.reaction', (reactions) => this.emit(ClientEvent.MESSAGE_REACTION, reactions));
299
+ this.sock.ev.on('messages.upsert', async (event) => {
300
+ try {
301
+
302
+ const { messages, type } = event;
303
+ const msg = messages[0];
304
+ if (!msg.message || msg.message.protocolMessage) {
305
+ this.emit(ClientEvent.NOTIFICATION, msg);
306
+ } else {
307
+ if (msg.broadcast || msg.key.remoteJid == 'status@broadcast') {
308
+ this.emit(ClientEvent.BROADCAST_MESSAGE, msg);
309
+ } else {
310
+ const nmsg = await MessageNormalizer.normalize(msg, this);
311
+ this.store.setMessage(nmsg.chatId, nmsg);
312
+ // Mensagens de conversacao
313
+ switch (type) {
314
+ case 'append':
315
+ this.emit(ClientEvent.MESSAGE_SENT, nmsg);
316
+ break;
317
+
318
+ case 'notify':
319
+ if (msg.key.fromMe) {
320
+ this.emit(ClientEvent.MESSAGE_SENT, nmsg);
321
+ } else {
322
+ this.emit(ClientEvent.MESSAGE_RECEIVED, nmsg);
323
+ }
324
+
325
+ break;
326
+ default:
327
+ this.emit(ClientEvent.NOTIFICATION, nmsg);
328
+ break;
329
+ }
330
+
331
+ }
332
+ }
333
+ } catch (error) {
334
+ this.emit(ClientEvent.ERROR, error);
335
+ }
336
+
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Desconecta o cliente do WhatsApp de forma manual, sem apagar a sessão.
342
+ * @returns {Promise<void>}
343
+ */
344
+ disconnect() {
345
+ try {
346
+ this.manualDisconnect = true;
347
+ return this.sock?.end();
348
+ } catch (error) {
349
+ this.emit(ClientEvent.ERROR, error);
350
+ }
351
+ }
352
+
353
+ /** Logout e remoção de dados de sessão */
354
+ async logout() {
355
+ try {
356
+ if (this.sock.logout) {
357
+ await this.sock.logout();
358
+ }
359
+ // Aqui você pode adicionar a limpeza local da sessão
360
+ } catch (err) {
361
+ this.emit(ClientEvent.ERROR, err);
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Valida a conexão antes de executar uma ação.
367
+ * @private
368
+ * @throws {Error} Se o cliente não estiver conectado.
369
+ */
370
+ _validateConnection() {
371
+ if (!this.sock || !this.connected) {
372
+ throw new Error('Cliente não está conectado.');
373
+ }
374
+ }
375
+
376
+ async decryptPollVote(vote, voteParams) {
377
+ return await decryptPollVote(vote, voteParams);
378
+ }
379
+
380
+ jidNormalizedUser(id) {
381
+ return jidNormalizedUser(id);
382
+ }
383
+
384
+ async downloadContentFromMessage(content, type) {
385
+ return await downloadContentFromMessage(content, type);
386
+ }
387
+
388
+ async fileExists(path) {
389
+ try {
390
+ await fs.access(path, constants.F_OK);
391
+ return true;
392
+ } catch {
393
+ return false;
394
+ }
395
+ }
396
+
397
+ }
398
+
399
+ /**
400
+ * Enumeração estática dos eventos emitidos pelo Client.
401
+ */
402
+ class ClientEvent {
403
+ static INIT = 'init';
404
+ static CONNECTING = 'connecting';
405
+ static STATUS_CHANGE = 'status_change';
406
+ static ERROR = 'error';
407
+ static MESSAGE_RECEIVED = 'message_received';
408
+ static MESSAGE_SENT = 'message_sent';
409
+ static MESSAGE_UPDATE = 'message_update';
410
+ static MESSAGE_DELETE = 'message_delete';
411
+ static MESSAGE_REACTION = 'message_reaction';
412
+ static CALL = 'call';
413
+ static GROUP_UPDATE = 'group_update';
414
+ static GROUP_PARTICIPANTS_UPDATE = 'group_participants_update';
415
+ static PRESENCE_UPDATE = 'presence_update';
416
+ static CHAT_UPDATE = 'chat_update';
417
+ static CHAT_DELETE = 'chat_delete';
418
+ static CONTACT_UPDATE = 'contact_update';
419
+ static BLOCKLIST_UPDATE = 'blocklist_update';
420
+ static PAIRING_CODE = 'pairing_code';
421
+ static PAIRING_SUCCESS = 'pairing_success';
422
+ static DISCONNECTED = 'disconnected';
423
+ static CONNECTED = 'connected';
424
+ static MESSAGES_HISTORY_SYNC_DONE = 'messages_history_sync_done';
425
+ static BROADCAST_MESSAGE = 'broadcast_message';
426
+ static NOTIFICATION = 'notification';
427
+ }
428
+
429
+ /**
430
+ * Enumeração estática dos motivos de desconexão.
431
+ */
432
+ class DisconnectReasons {
433
+ static MANUAL_DISCONNECT = 'manual_disconnect';
434
+ static LOGGED_OUT = 'logged_out';
435
+ static PAIRING_FAILED = 'pairing_failed';
436
+ static CONNECTION_ERROR = 'connection_error';
437
+ static RESTART_REQUIRED = 'restart_required';
438
+ static UNAVAILABLE_SERVICE = 'unavailable_service';
439
+ static UNKNOWN = 'unknown';
440
+ }
441
+
442
+ module.exports = {
443
+ Client,
444
+ PresenceStatus,
445
+ ClientEvent,
446
+ DisconnectReasons,
447
+ InteractiveMessage,
448
+ QuickReplyButton,
449
+ UrlButton,
450
+ CopyCodeButton,
451
+ CallButton,
452
+ ListButton,
453
+ ListSection,
454
+ ListRow,
455
+ LocationButton
456
+ }
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@areumtecnologia/baileys",
3
+ "version": "1.0.0",
4
+ "description": "More baileys fork",
5
+ "license": "ISC",
6
+ "author": "Áreum Tecnologia",
7
+ "type": "commonjs",
8
+ "main": "index.js",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "dependencies": {
13
+ "@itsukichan/baileys": "^7.3.2",
14
+ "baileys": "^7.0.0-rc.9"
15
+ }
16
+ }
package/tests/app.js ADDED
@@ -0,0 +1,68 @@
1
+ const { Client, ClientEvent } = require('../index'); // Caminho para sua classe Client
2
+ // 1. Instanciação do Cliente atualizada para usar a nova classe
3
+ const client = new Client({
4
+ sessionName: sessionId,
5
+ restartOnClose: true,
6
+ markOnlineOnConnect: false,
7
+ enviroment: [account.name || 'MacOS', 'Chrome', '118.0.0.0'],
8
+ store: {
9
+ // getMessage: async (chatId, mid) => {
10
+ // const msg = (await messages.select([{ chat_id: chatId }, AND, { mid }]))[0];
11
+ // return msg;
12
+ // },
13
+ // setMessage: async (chatId, msg) => {
14
+ // // Nao implementa pois ja registra as mensagens nos eventos message_received e message_sent
15
+ // }
16
+ }
17
+ });
18
+
19
+ client.on(ClientEvent.STATUS_CHANGE, async (status) => {
20
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Status alterado para: ${status}`);
21
+ });
22
+
23
+ client.on(ClientEvent.PAIRING_CODE, async ({ qr }) => {
24
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] QR Code recebido. Enviando via webhook...`);
25
+ const base64 = await QRCode.toDataURL(qr);
26
+ client.qrCodeAttempts = (client.qrCodeAttempts || 0) + 1;
27
+ client.qrCode = { base64, url: qr, attempts: client.qrCodeAttempts, status: 'waiting' };
28
+ });
29
+
30
+ client.on(ClientEvent.PAIRING_SUCCESS, async (event) => {
31
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] QR Code lido com sucesso. Enviando via webhook...`);
32
+ });
33
+
34
+ client.on(ClientEvent.CONNECTED, async () => {
35
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Conectado com sucesso.`);
36
+ client.qrCode = null; // Limpa o QR code após a conexão
37
+
38
+ // Envia mensagem de boas-vindas usando o novo handler
39
+ const user = client.sock.user;
40
+ const welcomeMessage = `🤖 Olá, ${user.name || 'usuário'}!\nSua sessão (${sessionId}) foi conectada com sucesso.`;
41
+ await client.messages.sendTextMessage(user.id, welcomeMessage);
42
+
43
+ });
44
+
45
+ client.on(ClientEvent.DISCONNECTED, async (reason) => {
46
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Desconectado. Motivo: ${reason.statusType}`, reason.details || '');
47
+ });
48
+
49
+ client.on(ClientEvent.MESSAGE_RECEIVED, async (msg) => {
50
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Mensagem recebida de ${msg.from}`);
51
+ });
52
+
53
+ client.on(ClientEvent.MESSAGE_SENT, async (msg) => {
54
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Mensagem enviada para ${msg.to}`);
55
+ });
56
+
57
+ client.on(ClientEvent.CALL, async (call) => {
58
+ console.log(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Chamada recebida de ${call.from}`);
59
+
60
+ });
61
+
62
+ client.on(ClientEvent.ERROR, (error) => {
63
+ console.error(new Date().toLocaleDateString('pt-br'), `[${sessionId}] Ocorreu um erro na instância do cliente:`, error, error?.lastDisconnect?.output);
64
+ });
65
+
66
+
67
+ // Inicia a conexão
68
+ await client.connect();
Binary file
@@ -0,0 +1,72 @@
1
+ // Classe única para construir uma mensagem com múltiplos botões de diferentes tipos, sem método build
2
+ class MessageButton {
3
+ constructor({ title = '', text = '', footer = '' } = {}) {
4
+ this.title = title;
5
+ this.text = text;
6
+ this.footer = footer;
7
+ this.buttons = [];
8
+ }
9
+
10
+ // Adiciona um botão de resposta rápida
11
+ addQuickReply(id, text) {
12
+ this.buttons.push({ id, text });
13
+ return this;
14
+ }
15
+
16
+ // Adiciona um botão de URL
17
+ addUrlButton(display_text, url) {
18
+ this.buttons.push({
19
+ name: 'cta_url',
20
+ buttonParamsJson: JSON.stringify({ display_text, url })
21
+ });
22
+ return this;
23
+ }
24
+
25
+ // Adiciona um botão de copiar código
26
+ addCopyCodeButton(display_text, code) {
27
+ this.buttons.push({
28
+ name: 'copy_code',
29
+ buttonParamsJson: JSON.stringify({ display_text, code })
30
+ });
31
+ return this;
32
+ }
33
+
34
+ // Adiciona um botão de chamada telefônica
35
+ addCallButton(display_text, phone_number) {
36
+ this.buttons.push({
37
+ name: 'call',
38
+ buttonParamsJson: JSON.stringify({ display_text, phone_number })
39
+ });
40
+ return this;
41
+ }
42
+
43
+ // Permite usar o objeto diretamente
44
+ toJSON() {
45
+ return {
46
+ title: this.title,
47
+ text: this.text,
48
+ footer: this.footer,
49
+ buttons: this.buttons
50
+ };
51
+ }
52
+ }
53
+
54
+ module.exports = { MessageButton };
55
+
56
+ /*
57
+ Exemplo de uso:
58
+
59
+ const { MessageButton } = require('./buttons');
60
+
61
+ const msg = new MessageButton({
62
+ title: 'Header Title',
63
+ text: 'Pick one option below',
64
+ footer: 'Footer text'
65
+ })
66
+ .addQuickReply('quick_1', 'Quick Reply')
67
+ .addUrlButton('Open Site', 'https://example.com')
68
+ .addCopyCodeButton('Copy Code', '123456')
69
+ .addCallButton('Call Us', '+5511999999999');
70
+
71
+ await sendButtons(this.sock, jid, msg); // msg será convertido automaticamente
72
+ */
Binary file