@systemzero/baileys 1.0.5 β 1.0.6
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/README.md +506 -601
- package/lib/Socket/chats.js +12 -1
- package/lib/Socket/groups.js +13 -4
- package/lib/Socket/messages-recv.js +36 -2
- package/lib/Socket/messages-recv.js.bak +1273 -0
- package/lib/Socket/messages-send.js +1 -0
- package/lib/Utils/bad-mac-handler.js +158 -0
- package/lib/Utils/get-best-version.js +41 -0
- package/lib/Utils/get-name.d.ts +1 -0
- package/lib/Utils/get-name.js +54 -0
- package/lib/Utils/group-status-detection.js +113 -0
- package/lib/Utils/index.js +7 -0
- package/lib/Utils/logger.js +4 -1
- package/lib/Utils/messages-media.js +38 -0
- package/lib/Utils/messages.js +113 -7
- package/lib/Utils/payment-detection.js +212 -0
- package/lib/Utils/payment-guard.d.ts +15 -0
- package/lib/Utils/payment-guard.js +142 -0
- package/lib/Utils/resolve-lid-phone.js +30 -0
- package/lib/WABinary/jid-utils.js +245 -1
- package/package.json +3 -2
- package/lib/Defaults/index.d.ts.map +0 -1
- package/lib/Defaults/index.js.map +0 -1
- package/lib/Signal/Group/ciphertext-message.d.ts.map +0 -1
- package/lib/Signal/Group/ciphertext-message.js.map +0 -1
- package/lib/Signal/Group/group-session-builder.d.ts.map +0 -1
- package/lib/Signal/Group/group-session-builder.js.map +0 -1
- package/lib/Signal/Group/group_cipher.d.ts.map +0 -1
- package/lib/Signal/Group/group_cipher.js.map +0 -1
- package/lib/Signal/Group/index.d.ts.map +0 -1
- package/lib/Signal/Group/index.js.map +0 -1
- package/lib/Signal/Group/keyhelper.d.ts.map +0 -1
- package/lib/Signal/Group/keyhelper.js.map +0 -1
- package/lib/Signal/Group/sender-chain-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-chain-key.js.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-distribution-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-message.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-message.js.map +0 -1
- package/lib/Signal/Group/sender-key-name.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-name.js.map +0 -1
- package/lib/Signal/Group/sender-key-record.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-record.js.map +0 -1
- package/lib/Signal/Group/sender-key-state.d.ts.map +0 -1
- package/lib/Signal/Group/sender-key-state.js.map +0 -1
- package/lib/Signal/Group/sender-message-key.d.ts.map +0 -1
- package/lib/Signal/Group/sender-message-key.js.map +0 -1
- package/lib/Signal/libsignal.d.ts.map +0 -1
- package/lib/Signal/libsignal.js.map +0 -1
- package/lib/Signal/lid-mapping.d.ts.map +0 -1
- package/lib/Signal/lid-mapping.js.map +0 -1
- package/lib/Socket/Client/index.d.ts.map +0 -1
- package/lib/Socket/Client/index.js.map +0 -1
- package/lib/Socket/Client/types.d.ts.map +0 -1
- package/lib/Socket/Client/types.js.map +0 -1
- package/lib/Socket/Client/websocket.d.ts.map +0 -1
- package/lib/Socket/Client/websocket.js.map +0 -1
- package/lib/Socket/business.d.ts.map +0 -1
- package/lib/Socket/business.js.map +0 -1
- package/lib/Socket/chats.d.ts.map +0 -1
- package/lib/Socket/chats.js.map +0 -1
- package/lib/Socket/communities.d.ts.map +0 -1
- package/lib/Socket/communities.js.map +0 -1
- package/lib/Socket/groups.d.ts.map +0 -1
- package/lib/Socket/groups.js.map +0 -1
- package/lib/Socket/index.d.ts.map +0 -1
- package/lib/Socket/index.js.map +0 -1
- package/lib/Socket/messages-recv.d.ts.map +0 -1
- package/lib/Socket/messages-recv.js.map +0 -1
- package/lib/Socket/messages-send.d.ts.map +0 -1
- package/lib/Socket/messages-send.js.map +0 -1
- package/lib/Socket/mex.d.ts.map +0 -1
- package/lib/Socket/mex.js.map +0 -1
- package/lib/Socket/newsletter.d.ts.map +0 -1
- package/lib/Socket/newsletter.js.map +0 -1
- package/lib/Socket/socket.d.ts.map +0 -1
- package/lib/Socket/socket.js.map +0 -1
- package/lib/Types/Auth.d.ts.map +0 -1
- package/lib/Types/Auth.js.map +0 -1
- package/lib/Types/Bussines.d.ts.map +0 -1
- package/lib/Types/Bussines.js.map +0 -1
- package/lib/Types/Call.d.ts.map +0 -1
- package/lib/Types/Call.js.map +0 -1
- package/lib/Types/Chat.d.ts.map +0 -1
- package/lib/Types/Chat.js.map +0 -1
- package/lib/Types/Contact.d.ts.map +0 -1
- package/lib/Types/Contact.js.map +0 -1
- package/lib/Types/Events.d.ts.map +0 -1
- package/lib/Types/Events.js.map +0 -1
- package/lib/Types/GroupMetadata.d.ts.map +0 -1
- package/lib/Types/GroupMetadata.js.map +0 -1
- package/lib/Types/Label.d.ts.map +0 -1
- package/lib/Types/Label.js.map +0 -1
- package/lib/Types/LabelAssociation.d.ts.map +0 -1
- package/lib/Types/LabelAssociation.js.map +0 -1
- package/lib/Types/Message.d.ts.map +0 -1
- package/lib/Types/Message.js.map +0 -1
- package/lib/Types/Newsletter.d.ts.map +0 -1
- package/lib/Types/Newsletter.js.map +0 -1
- package/lib/Types/Product.d.ts.map +0 -1
- package/lib/Types/Product.js.map +0 -1
- package/lib/Types/Signal.d.ts.map +0 -1
- package/lib/Types/Signal.js.map +0 -1
- package/lib/Types/Socket.d.ts.map +0 -1
- package/lib/Types/Socket.js.map +0 -1
- package/lib/Types/State.d.ts.map +0 -1
- package/lib/Types/State.js.map +0 -1
- package/lib/Types/USync.d.ts.map +0 -1
- package/lib/Types/USync.js.map +0 -1
- package/lib/Types/index.d.ts.map +0 -1
- package/lib/Types/index.js.map +0 -1
- package/lib/Utils/auth-utils.d.ts.map +0 -1
- package/lib/Utils/auth-utils.js.map +0 -1
- package/lib/Utils/browser-utils.d.ts.map +0 -1
- package/lib/Utils/browser-utils.js.map +0 -1
- package/lib/Utils/business.d.ts.map +0 -1
- package/lib/Utils/business.js.map +0 -1
- package/lib/Utils/chat-utils.d.ts.map +0 -1
- package/lib/Utils/chat-utils.js.map +0 -1
- package/lib/Utils/crypto.d.ts.map +0 -1
- package/lib/Utils/crypto.js.map +0 -1
- package/lib/Utils/decode-wa-message.d.ts.map +0 -1
- package/lib/Utils/decode-wa-message.js.map +0 -1
- package/lib/Utils/event-buffer.d.ts.map +0 -1
- package/lib/Utils/event-buffer.js.map +0 -1
- package/lib/Utils/generics.d.ts.map +0 -1
- package/lib/Utils/generics.js.map +0 -1
- package/lib/Utils/history.d.ts.map +0 -1
- package/lib/Utils/history.js.map +0 -1
- package/lib/Utils/index.d.ts.map +0 -1
- package/lib/Utils/index.js.map +0 -1
- package/lib/Utils/link-preview.d.ts.map +0 -1
- package/lib/Utils/link-preview.js.map +0 -1
- package/lib/Utils/logger.d.ts.map +0 -1
- package/lib/Utils/logger.js.map +0 -1
- package/lib/Utils/lt-hash.d.ts.map +0 -1
- package/lib/Utils/lt-hash.js.map +0 -1
- package/lib/Utils/make-mutex.d.ts.map +0 -1
- package/lib/Utils/make-mutex.js.map +0 -1
- package/lib/Utils/message-retry-manager.d.ts.map +0 -1
- package/lib/Utils/message-retry-manager.js.map +0 -1
- package/lib/Utils/messages-media.d.ts.map +0 -1
- package/lib/Utils/messages-media.js.map +0 -1
- package/lib/Utils/messages.d.ts.map +0 -1
- package/lib/Utils/messages.js.map +0 -1
- package/lib/Utils/noise-handler.d.ts.map +0 -1
- package/lib/Utils/noise-handler.js.map +0 -1
- package/lib/Utils/pre-key-manager.d.ts.map +0 -1
- package/lib/Utils/pre-key-manager.js.map +0 -1
- package/lib/Utils/process-message.d.ts.map +0 -1
- package/lib/Utils/process-message.js.map +0 -1
- package/lib/Utils/signal.d.ts.map +0 -1
- package/lib/Utils/signal.js.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.d.ts.map +0 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +0 -1
- package/lib/Utils/validate-connection.d.ts.map +0 -1
- package/lib/Utils/validate-connection.js.map +0 -1
- package/lib/WABinary/constants.d.ts.map +0 -1
- package/lib/WABinary/constants.js.map +0 -1
- package/lib/WABinary/decode.d.ts.map +0 -1
- package/lib/WABinary/decode.js.map +0 -1
- package/lib/WABinary/encode.d.ts.map +0 -1
- package/lib/WABinary/encode.js.map +0 -1
- package/lib/WABinary/generic-utils.d.ts.map +0 -1
- package/lib/WABinary/generic-utils.js.map +0 -1
- package/lib/WABinary/index.d.ts.map +0 -1
- package/lib/WABinary/index.js.map +0 -1
- package/lib/WABinary/jid-utils.d.ts.map +0 -1
- package/lib/WABinary/jid-utils.js.map +0 -1
- package/lib/WABinary/types.d.ts.map +0 -1
- package/lib/WABinary/types.js.map +0 -1
- package/lib/WAM/BinaryInfo.d.ts.map +0 -1
- package/lib/WAM/BinaryInfo.js.map +0 -1
- package/lib/WAM/constants.d.ts.map +0 -1
- package/lib/WAM/constants.js.map +0 -1
- package/lib/WAM/encode.d.ts.map +0 -1
- package/lib/WAM/encode.js.map +0 -1
- package/lib/WAM/index.d.ts.map +0 -1
- package/lib/WAM/index.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +0 -1
- package/lib/WAUSync/Protocols/index.d.ts.map +0 -1
- package/lib/WAUSync/Protocols/index.js.map +0 -1
- package/lib/WAUSync/USyncQuery.d.ts.map +0 -1
- package/lib/WAUSync/USyncQuery.js.map +0 -1
- package/lib/WAUSync/USyncUser.d.ts.map +0 -1
- package/lib/WAUSync/USyncUser.js.map +0 -1
- package/lib/WAUSync/index.d.ts.map +0 -1
- package/lib/WAUSync/index.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
|
@@ -782,6 +782,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
782
782
|
else if (message.contactsArrayMessage) return 'contact_array';
|
|
783
783
|
else if (message.liveLocationMessage) return 'livelocation';
|
|
784
784
|
else if (message.stickerMessage) return 'sticker';
|
|
785
|
+
else if (message.lottieStickerMessage) return 'sticker';
|
|
785
786
|
else if (message.listMessage) return 'list';
|
|
786
787
|
else if (message.listResponseMessage) return 'list_response';
|
|
787
788
|
else if (message.buttonsResponseMessage) return 'buttons_response';
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UtilitΓ‘rio para lidar com erros "Bad MAC", comuns em bots WhatsApp usando
|
|
3
|
+
* Baileys quando a sessΓ£o Signal de um par fica desincronizada (ex: o
|
|
4
|
+
* outro lado reinstalou o WhatsApp, trocou de aparelho, ou houve perda de
|
|
5
|
+
* mensagens na troca de chaves). NΓ£o Γ© uma falha do bot β Γ© esperado que
|
|
6
|
+
* aconteΓ§a ocasionalmente em qualquer cliente Signal Protocol.
|
|
7
|
+
*
|
|
8
|
+
* Este mΓ³dulo fornece funΓ§Γ΅es para detectar, contar e lidar graciosamente
|
|
9
|
+
* com esses erros, sem derrubar o processo do bot.
|
|
10
|
+
*
|
|
11
|
+
* @author Dev Gui (original), integrado na lib para System Zero. By JosuΓ© </>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { errorLog, warningLog } from './logger.js';
|
|
17
|
+
|
|
18
|
+
export class BadMacHandler {
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.errorCount = 0;
|
|
21
|
+
this.maxRetries = options.maxRetries ?? 5;
|
|
22
|
+
this.resetInterval = options.resetInterval ?? 300000; // 5 min
|
|
23
|
+
this.lastReset = Date.now();
|
|
24
|
+
// pasta de auth configurΓ‘vel β por padrΓ£o segue o padrΓ£o Baileys comum
|
|
25
|
+
this.authFolder = options.authFolder ?? path.resolve(process.cwd(), 'assets', 'auth', 'baileys');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isBadMacError(error) {
|
|
29
|
+
const errorMessage = error?.message || error?.toString() || '';
|
|
30
|
+
return (
|
|
31
|
+
errorMessage.includes('Bad MAC') ||
|
|
32
|
+
errorMessage.includes('MAC verification failed') ||
|
|
33
|
+
errorMessage.includes('decryption failed')
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
isSessionError(error) {
|
|
38
|
+
const errorMessage = error?.message || error?.toString() || '';
|
|
39
|
+
return (
|
|
40
|
+
errorMessage.includes('Session') ||
|
|
41
|
+
errorMessage.includes('signal protocol') ||
|
|
42
|
+
errorMessage.includes('decrypt') ||
|
|
43
|
+
this.isBadMacError(error)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Remove arquivos de sessΓ£o Signal problemΓ‘ticos, preservando SEMPRE as
|
|
49
|
+
* credenciais principais (creds.json, app-state-sync-key/version) β sΓ³
|
|
50
|
+
* descarta arquivos de sessΓ£o por par (que serΓ£o renegociados
|
|
51
|
+
* automaticamente na prΓ³xima troca de chaves).
|
|
52
|
+
*/
|
|
53
|
+
clearProblematicSessionFiles() {
|
|
54
|
+
try {
|
|
55
|
+
if (!fs.existsSync(this.authFolder)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const PRESERVE_PATTERNS = ['app-state-sync-key', 'creds.json', 'app-state-sync-version'];
|
|
60
|
+
const files = fs.readdirSync(this.authFolder);
|
|
61
|
+
let removedCount = 0;
|
|
62
|
+
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
const filePath = path.join(this.authFolder, file);
|
|
65
|
+
if (!fs.statSync(filePath).isFile()) continue;
|
|
66
|
+
|
|
67
|
+
const mustPreserve = PRESERVE_PATTERNS.some((pattern) => file.includes(pattern));
|
|
68
|
+
if (mustPreserve) continue;
|
|
69
|
+
|
|
70
|
+
// sΓ³ remove arquivos de sessΓ£o por par (ex: session-*.json)
|
|
71
|
+
if (file.startsWith('session-') || file.includes('sender-key')) {
|
|
72
|
+
fs.unlinkSync(filePath);
|
|
73
|
+
removedCount++;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (removedCount > 0) {
|
|
78
|
+
warningLog(`${removedCount} arquivo(s) de sessΓ£o problemΓ‘ticos removidos. Credenciais principais preservadas.`);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return false;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
errorLog(`Erro ao limpar arquivos de sessΓ£o: ${error.message}`);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
incrementErrorCount() {
|
|
90
|
+
this.errorCount++;
|
|
91
|
+
errorLog(`Bad MAC error count: ${this.errorCount}/${this.maxRetries}`);
|
|
92
|
+
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
if (now - this.lastReset > this.resetInterval) {
|
|
95
|
+
this.resetErrorCount();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
resetErrorCount() {
|
|
100
|
+
const previousCount = this.errorCount;
|
|
101
|
+
this.errorCount = 0;
|
|
102
|
+
this.lastReset = Date.now();
|
|
103
|
+
|
|
104
|
+
if (previousCount > 0) {
|
|
105
|
+
warningLog(`Reset do contador de Bad MAC errors. Contador anterior: ${previousCount}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
hasReachedLimit() {
|
|
110
|
+
return this.errorCount >= this.maxRetries;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @returns {boolean} true se o erro foi tratado (Bad MAC engolido),
|
|
115
|
+
* false se NΓO era Bad MAC (deve ser relanΓ§ado pelo caller)
|
|
116
|
+
*/
|
|
117
|
+
handleError(error, context = 'unknown') {
|
|
118
|
+
if (!this.isBadMacError(error)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
errorLog(`Bad MAC error detectado em ${context}: ${error.message}`);
|
|
123
|
+
this.incrementErrorCount();
|
|
124
|
+
|
|
125
|
+
if (this.hasReachedLimit()) {
|
|
126
|
+
warningLog(`Limite de Bad MAC errors atingido (${this.maxRetries}). Considere reiniciar o bot ou limpar sessΓ΅es com clearProblematicSessionFiles().`);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
warningLog(`Ignorando Bad MAC error e continuando operaΓ§Γ£o... (${this.errorCount}/${this.maxRetries})`);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Envolve uma funΓ§Γ£o async β engole Bad MAC, relanΓ§a qualquer outro erro. */
|
|
135
|
+
createSafeWrapper(fn, context) {
|
|
136
|
+
return async (...args) => {
|
|
137
|
+
try {
|
|
138
|
+
return await fn(...args);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (this.handleError(error, context)) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
getStats() {
|
|
149
|
+
return {
|
|
150
|
+
errorCount: this.errorCount,
|
|
151
|
+
maxRetries: this.maxRetries,
|
|
152
|
+
lastReset: new Date(this.lastReset).toISOString(),
|
|
153
|
+
timeUntilReset: Math.max(0, this.resetInterval - (Date.now() - this.lastReset)),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export const badMacHandler = new BadMacHandler();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// lib/Utils/get-best-version.js
|
|
2
|
+
//
|
|
3
|
+
// fetchLatestWaWebVersion() e fetchLatestBaileysVersion() SEMPRE retornam um
|
|
4
|
+
// objeto com `version` preenchido, mesmo quando a busca falha β nesse caso
|
|
5
|
+
// devolvem isLatest:false e um valor antigo fixo embutido na lib. Checar sΓ³
|
|
6
|
+
// `if (result.version)` nunca detecta a falha, porque version sempre existe.
|
|
7
|
+
//
|
|
8
|
+
// Este helper tenta as duas fontes, na ordem, e sΓ³ aceita um resultado se
|
|
9
|
+
// `isLatest === true` (ou seja, se realmente buscou fresco da rede). SΓ³ cai
|
|
10
|
+
// no valor fixo antigo se AMBAS as fontes falharem de verdade.
|
|
11
|
+
|
|
12
|
+
import { fetchLatestWaWebVersion } from './generics.js';
|
|
13
|
+
import { fetchLatestBaileysVersion } from './generics.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} [options] - passado direto pras duas funΓ§Γ΅es de fetch
|
|
17
|
+
* @returns {Promise<{ version: number[], isLatest: boolean, source: string }>}
|
|
18
|
+
*/
|
|
19
|
+
export const getBestWaVersion = async (options = {}) => {
|
|
20
|
+
try {
|
|
21
|
+
const web = await fetchLatestWaWebVersion(options);
|
|
22
|
+
if (web?.isLatest && web?.version) {
|
|
23
|
+
return { version: web.version, isLatest: true, source: 'web.whatsapp.com' };
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// segue pra prΓ³xima fonte
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const github = await fetchLatestBaileysVersion(options);
|
|
31
|
+
if (github?.isLatest && github?.version) {
|
|
32
|
+
return { version: github.version, isLatest: true, source: 'github' };
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
// segue pro fallback fixo
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// as duas fontes falharam de verdade β usa o valor fixo embutido,
|
|
39
|
+
// mas avisa explicitamente que NΓO Γ© a versΓ£o mais atual
|
|
40
|
+
return { version: [2, 3000, 1027934701], isLatest: false, source: 'fallback-fixo' };
|
|
41
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getName: (msg: any, contactStore?: Record<string, { name?: string; notify?: string; verifiedName?: string }>) => string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// lib/Utils/get-name.js
|
|
2
|
+
// Resolve o nome do remetente com cobertura total (nunca retorna vazio).
|
|
3
|
+
// Ordem de prioridade:
|
|
4
|
+
// 1) Nome salvo localmente (store/contatos) β mais confiΓ‘vel
|
|
5
|
+
// 2) verifiedName (conta business confirmada pela Meta)
|
|
6
|
+
// 3) notify / pushName da prΓ³pria mensagem
|
|
7
|
+
// 4) Nome resolvido via cache LID -> JID (se sender for @lid)
|
|
8
|
+
// 5) NΓΊmero de telefone formatado (fallback final, nunca undefined)
|
|
9
|
+
|
|
10
|
+
import { jidDecode, isLidUser, sharedLidPhoneCache, lidToJid } from '../WABinary/jid-utils.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {object} msg - mensagem completa do Baileys (proto.IWebMessageInfo)
|
|
14
|
+
* @param {object} [contactStore] - opcional: { [jid]: { name, notify, verifiedName } }
|
|
15
|
+
* @returns {string} nome final, garantido nΓ£o-vazio
|
|
16
|
+
*/
|
|
17
|
+
export const getName = (msg, contactStore) => {
|
|
18
|
+
try {
|
|
19
|
+
const key = msg?.key || {};
|
|
20
|
+
let sender = key.participant || key.remoteJid || '';
|
|
21
|
+
|
|
22
|
+
// se vier @lid, tenta resolver pro JID real (telefone) primeiro,
|
|
23
|
+
// pois o contactStore normalmente Γ© indexado por @s.whatsapp.net
|
|
24
|
+
let resolvedSender = sender;
|
|
25
|
+
if (isLidUser(sender)) {
|
|
26
|
+
const phone = sharedLidPhoneCache.getPhoneForLid(sender) || lidToJid(sender);
|
|
27
|
+
if (phone && phone !== sender) resolvedSender = phone;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 1) contato salvo localmente
|
|
31
|
+
const contact = contactStore?.[resolvedSender] || contactStore?.[sender];
|
|
32
|
+
if (contact?.name && contact.name.trim()) return contact.name.trim();
|
|
33
|
+
|
|
34
|
+
// 2) verifiedName (conta business)
|
|
35
|
+
if (contact?.verifiedName && contact.verifiedName.trim()) return contact.verifiedName.trim();
|
|
36
|
+
|
|
37
|
+
// 3) pushName / notify da mensagem em si
|
|
38
|
+
const pushName = msg?.pushName || contact?.notify;
|
|
39
|
+
if (pushName && pushName.trim() && pushName.trim() !== 'WhatsApp User') {
|
|
40
|
+
return pushName.trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 4) fallback: nΓΊmero de telefone formatado a partir do JID resolvido
|
|
44
|
+
const decoded = jidDecode(resolvedSender);
|
|
45
|
+
if (decoded?.user) {
|
|
46
|
+
return `+${decoded.user}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 5) ΓΊltimo recurso absoluto β nunca undefined/empty
|
|
50
|
+
return 'UsuΓ‘rio desconhecido';
|
|
51
|
+
} catch {
|
|
52
|
+
return 'UsuΓ‘rio desconhecido';
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DetecΓ§Γ£o robusta de mensagens de status-em-grupo (marcaΓ§Γ£o de status no grupo).
|
|
3
|
+
*
|
|
4
|
+
* Cobre:
|
|
5
|
+
* - groupStatusMentionMessage / groupStatusMessage / groupStatusMessageV2
|
|
6
|
+
* - isGroupStatus: true | 1 em qualquer nΓvel
|
|
7
|
+
* - statusAttributions com type GROUP_STATUS / type 5 / groupStatus: true
|
|
8
|
+
* - mensagens aninhadas em wrappers (ephemeral, viewOnce, etc)
|
|
9
|
+
*
|
|
10
|
+
* @author Dev Gui (original), integrado na lib para System Zero. By JosuΓ© </>
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const MAX_MESSAGE_UNWRAP_DEPTH = 5;
|
|
14
|
+
const MAX_FLAG_SCAN_DEPTH = 8;
|
|
15
|
+
|
|
16
|
+
const STRONG_GROUP_STATUS_MESSAGE_KEYS = new Set([
|
|
17
|
+
'groupStatusMentionMessage',
|
|
18
|
+
'groupStatusMessage',
|
|
19
|
+
'groupStatusMessageV2',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const WRAPPED_MESSAGE_KEYS = [
|
|
23
|
+
'ephemeralMessage',
|
|
24
|
+
'viewOnceMessage',
|
|
25
|
+
'viewOnceMessageV2',
|
|
26
|
+
'viewOnceMessageV2Extension',
|
|
27
|
+
'documentWithCaptionMessage',
|
|
28
|
+
'statusMentionMessage',
|
|
29
|
+
'groupStatusMentionMessage',
|
|
30
|
+
'groupStatusMessage',
|
|
31
|
+
'groupStatusMessageV2',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
export function isGroupStatusValue(value) {
|
|
35
|
+
return value === true || value === 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function canScanObject(value) {
|
|
39
|
+
return value && typeof value === 'object' && !(value instanceof ArrayBuffer) && !ArrayBuffer.isView(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function hasGroupStatusAttribution(statusAttributions) {
|
|
43
|
+
if (!Array.isArray(statusAttributions)) return false;
|
|
44
|
+
|
|
45
|
+
return statusAttributions.some(
|
|
46
|
+
(sa) =>
|
|
47
|
+
canScanObject(sa) &&
|
|
48
|
+
(Boolean(sa.groupStatus) || sa.attributionData === 'groupStatus' || sa.type === 'GROUP_STATUS' || sa.type === 5)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function hasGroupStatusContextInfo(contextInfo) {
|
|
53
|
+
return (
|
|
54
|
+
canScanObject(contextInfo) &&
|
|
55
|
+
(isGroupStatusValue(contextInfo.isGroupStatus) || hasGroupStatusAttribution(contextInfo.statusAttributions))
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function hasGroupStatusFlag(value, depth = 0, seenObjects = new WeakSet()) {
|
|
60
|
+
if (!canScanObject(value) || depth > MAX_FLAG_SCAN_DEPTH || seenObjects.has(value)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
seenObjects.add(value);
|
|
65
|
+
|
|
66
|
+
for (const [key, childValue] of Object.entries(value)) {
|
|
67
|
+
if (key === 'quotedMessage') continue;
|
|
68
|
+
|
|
69
|
+
if (STRONG_GROUP_STATUS_MESSAGE_KEYS.has(key) && canScanObject(childValue)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (key === 'isGroupStatus' && isGroupStatusValue(childValue)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (key === 'statusAttributions' && hasGroupStatusAttribution(childValue)) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (key === 'contextInfo' && hasGroupStatusContextInfo(childValue)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (hasGroupStatusFlag(childValue, depth + 1, seenObjects)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getCurrentMessageContentVariants(message, depth = 0, seenObjects = new WeakSet()) {
|
|
94
|
+
if (!canScanObject(message) || depth > MAX_MESSAGE_UNWRAP_DEPTH || seenObjects.has(message)) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
seenObjects.add(message);
|
|
99
|
+
|
|
100
|
+
const variants = [message];
|
|
101
|
+
|
|
102
|
+
for (const key of WRAPPED_MESSAGE_KEYS) {
|
|
103
|
+
const wrappedMessage = message[key]?.message;
|
|
104
|
+
variants.push(...getCurrentMessageContentVariants(wrappedMessage, depth + 1, seenObjects));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return variants;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Verifica se a webMessage Γ© uma marcaΓ§Γ£o de status em grupo, inclusive em wrappers ou nΓveis profundos. */
|
|
111
|
+
export function hasGroupStatusMessage(webMessage) {
|
|
112
|
+
return getCurrentMessageContentVariants(webMessage?.message).some((message) => hasGroupStatusFlag(message));
|
|
113
|
+
}
|
package/lib/Utils/index.js
CHANGED
|
@@ -16,4 +16,11 @@ export * from './event-buffer.js';
|
|
|
16
16
|
export * from './process-message.js';
|
|
17
17
|
export * from './message-retry-manager.js';
|
|
18
18
|
export * from './browser-utils.js';
|
|
19
|
+
export * from './get-name.js';
|
|
20
|
+
export * from './payment-guard.js';
|
|
21
|
+
export * from './payment-detection.js';
|
|
22
|
+
export * from './group-status-detection.js';
|
|
23
|
+
export * from './bad-mac-handler.js';
|
|
24
|
+
export * from './resolve-lid-phone.js';
|
|
25
|
+
export * from './get-best-version.js';
|
|
19
26
|
//# sourceMappingURL=index.js.map
|
package/lib/Utils/logger.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import P from 'pino';
|
|
2
|
-
|
|
2
|
+
const logger = P({ timestamp: () => `,"time":"${new Date().toJSON()}"` });
|
|
3
|
+
export const errorLog = (msg) => logger.error(msg);
|
|
4
|
+
export const warningLog = (msg) => logger.warn(msg);
|
|
5
|
+
export default logger;
|
|
3
6
|
//# sourceMappingURL=logger.js.map
|
|
@@ -7,12 +7,50 @@ import { tmpdir } from 'os';
|
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { Readable, Transform } from 'stream';
|
|
9
9
|
import { URL } from 'url';
|
|
10
|
+
import { promisify } from 'util';
|
|
10
11
|
import { proto } from '../../WAProto/index.js';
|
|
11
12
|
import { DEFAULT_ORIGIN, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP } from '../Defaults/index.js';
|
|
12
13
|
import { getBinaryNodeChild, getBinaryNodeChildBuffer, jidNormalizedUser } from '../WABinary/index.js';
|
|
13
14
|
import { aesDecryptGCM, aesEncryptGCM, hkdf } from './crypto.js';
|
|
14
15
|
import { generateMessageIDV2 } from './generics.js';
|
|
15
16
|
const getTmpFilesDirectory = () => tmpdir();
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Converte QUALQUER Γ‘udio de entrada pra opus/ogg mono 16kHz β o formato
|
|
21
|
+
* exato que o player de PTT do WhatsApp espera. Sem isso, marcar `ptt: true`
|
|
22
|
+
* num mp3/m4a sΓ³ troca o RΓTULO do mimetype sem mudar os bytes reais, e o
|
|
23
|
+
* WhatsApp mostra "algo errado com o arquivo de Γ‘udio" ao tentar decodificar.
|
|
24
|
+
*
|
|
25
|
+
* @param {string | Buffer} input - caminho de arquivo local, URL http(s), ou Buffer jΓ‘ em memΓ³ria
|
|
26
|
+
* @returns {Promise<string>} caminho do arquivo .ogg convertido (temporΓ‘rio β chame fs.unlink depois de usar)
|
|
27
|
+
*/
|
|
28
|
+
export async function transcodeAudioToOpus(input) {
|
|
29
|
+
const outputPath = join(getTmpFilesDirectory(), 'ptt-' + generateMessageIDV2() + '.ogg');
|
|
30
|
+
let inputPath = input;
|
|
31
|
+
let tempInputPath;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (Buffer.isBuffer(input)) {
|
|
35
|
+
tempInputPath = join(getTmpFilesDirectory(), 'ptt-src-' + generateMessageIDV2());
|
|
36
|
+
await fs.writeFile(tempInputPath, input);
|
|
37
|
+
inputPath = tempInputPath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// -vn: ignora qualquer vΓdeo/capa embutida (mp3 com artwork, por exemplo)
|
|
41
|
+
// -ac 1 -ar 16000: mono 16kHz β espec exata do PTT nativo do WhatsApp
|
|
42
|
+
// -c:a libopus -b:a 32k: codec real opus, nΓ£o sΓ³ o rΓ³tulo
|
|
43
|
+
const cmd = `ffmpeg -i "${inputPath}" -y -vn -ac 1 -ar 16000 -c:a libopus -b:a 32k -f ogg "${outputPath}"`;
|
|
44
|
+
await execAsync(cmd);
|
|
45
|
+
|
|
46
|
+
return outputPath;
|
|
47
|
+
} finally {
|
|
48
|
+
if (tempInputPath) {
|
|
49
|
+
await fs.unlink(tempInputPath).catch(() => {});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
16
54
|
export const getImageProcessingLibrary = async () => {
|
|
17
55
|
//@ts-ignore
|
|
18
56
|
const [jimp, sharp] = await Promise.all([import('jimp').catch(() => { }), import('sharp').catch(() => { })]);
|
package/lib/Utils/messages.js
CHANGED
|
@@ -8,7 +8,7 @@ import { WAMessageStatus, WAProto, ButtonHeaderType, ButtonType, CarouselCardTyp
|
|
|
8
8
|
import { isJidGroup, isJidNewsletter, isJidStatusBroadcast, jidNormalizedUser, isLidUser, isPnUser } from '../WABinary/index.js';
|
|
9
9
|
import { sha256 } from './crypto.js';
|
|
10
10
|
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
11
|
-
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData, getStream, toBuffer, getImageProcessingLibrary } from './messages-media.js';
|
|
11
|
+
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getRawMediaUploadData, getStream, toBuffer, getImageProcessingLibrary, transcodeAudioToOpus } from './messages-media.js';
|
|
12
12
|
const MIMETYPE_MAP = {
|
|
13
13
|
image: 'image/jpeg',
|
|
14
14
|
video: 'video/mp4',
|
|
@@ -77,9 +77,32 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
77
77
|
}
|
|
78
78
|
if (!uploadData.mimetype) {
|
|
79
79
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
|
80
|
-
} else if (mediaType === 'audio' && uploadData.mimetype === 'audio/ogg; codecs=opus') {
|
|
81
|
-
uploadData.mimetype = 'audio/mpeg';
|
|
82
80
|
}
|
|
81
|
+
// ptt: true β transcodifica de verdade pra opus/ogg mono 16kHz.
|
|
82
|
+
// Antes, isso sΓ³ trocava o RΓTULO do mimetype sem mudar os bytes reais,
|
|
83
|
+
// o que fazia o WhatsApp mostrar "algo errado com o arquivo de Γ‘udio"
|
|
84
|
+
// pra qualquer entrada que nΓ£o jΓ‘ fosse opus puro.
|
|
85
|
+
//
|
|
86
|
+
// IMPORTANTE: nΓ£o confia no `mimetype` que o CALLER declarou (a pessoa
|
|
87
|
+
// pode escrever 'audio/ogg' mesmo passando um mp3/m4a de origem) β sΓ³
|
|
88
|
+
// confia na extensΓ£o real do arquivo/URL de origem.
|
|
89
|
+
let pttTranscodedPath;
|
|
90
|
+
if (mediaType === 'audio' && uploadData.ptt === true) {
|
|
91
|
+
const mediaUrl = typeof uploadData.media === 'string'
|
|
92
|
+
? uploadData.media
|
|
93
|
+
: uploadData.media?.url?.toString?.() || '';
|
|
94
|
+
const sourceLooksLikeOpus = /\.(opus|ogg)(\?|$)/i.test(mediaUrl);
|
|
95
|
+
|
|
96
|
+
if (!sourceLooksLikeOpus) {
|
|
97
|
+
const sourceForTranscode = Buffer.isBuffer(uploadData.media)
|
|
98
|
+
? uploadData.media
|
|
99
|
+
: (typeof uploadData.media === 'string' ? uploadData.media : mediaUrl);
|
|
100
|
+
pttTranscodedPath = await transcodeAudioToOpus(sourceForTranscode);
|
|
101
|
+
uploadData.media = pttTranscodedPath;
|
|
102
|
+
}
|
|
103
|
+
uploadData.mimetype = 'audio/ogg; codecs=opus';
|
|
104
|
+
}
|
|
105
|
+
|
|
83
106
|
if (cacheableKey) {
|
|
84
107
|
const mediaBuff = await options.mediaCache.get(cacheableKey);
|
|
85
108
|
if (mediaBuff) {
|
|
@@ -118,6 +141,10 @@ if (!uploadData.mimetype) {
|
|
|
118
141
|
if (obj.stickerMessage) {
|
|
119
142
|
obj.stickerMessage.stickerSentTs = Date.now();
|
|
120
143
|
}
|
|
144
|
+
// lottie: stickerSentTs tambΓ©m no stickerMessage interno
|
|
145
|
+
if (obj.lottieStickerMessage?.message?.stickerMessage) {
|
|
146
|
+
obj.lottieStickerMessage.message.stickerMessage.stickerSentTs = Date.now();
|
|
147
|
+
}
|
|
121
148
|
if (cacheableKey) {
|
|
122
149
|
logger?.debug({ cacheableKey }, 'set cache');
|
|
123
150
|
await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish());
|
|
@@ -126,10 +153,10 @@ if (!uploadData.mimetype) {
|
|
|
126
153
|
}
|
|
127
154
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
128
155
|
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
|
|
129
|
-
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true;
|
|
156
|
+
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
|
|
130
157
|
const requiresPlaybackSpeed = mediaType === 'audio' && uploadData.ptt === true;
|
|
131
158
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
|
|
132
|
-
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
|
|
159
|
+
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation || requiresWaveformProcessing;
|
|
133
160
|
const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
134
161
|
logger,
|
|
135
162
|
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
@@ -188,6 +215,9 @@ if (!uploadData.mimetype) {
|
|
|
188
215
|
if (originalFilePath) {
|
|
189
216
|
await fs.unlink(originalFilePath);
|
|
190
217
|
}
|
|
218
|
+
if (pttTranscodedPath) {
|
|
219
|
+
await fs.unlink(pttTranscodedPath);
|
|
220
|
+
}
|
|
191
221
|
logger?.debug('removed tmp files');
|
|
192
222
|
}
|
|
193
223
|
catch (error) {
|
|
@@ -472,6 +502,70 @@ const prepareNativeFlowButtons = (message) => {
|
|
|
472
502
|
} else if (hasOptionalProperty(button, 'sections') && !!button.sections) {
|
|
473
503
|
return { name: 'single_select', buttonParamsJson: JSON.stringify({ title: buttonText || 'π Select', sections: button.sections, icon: buttonIcon }) };
|
|
474
504
|
}
|
|
505
|
+
// ββ BotΓ΅es estendidos (vanzxy) ββββββββββββββββββββββββββββββββββββββ
|
|
506
|
+
else if (hasOptionalProperty(button, 'reminder') && !!button.reminder) {
|
|
507
|
+
return { name: 'cta_reminder', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'β° Remind me', id: button.id || button.reminder, icon: buttonIcon }) };
|
|
508
|
+
}
|
|
509
|
+
else if (hasOptionalProperty(button, 'cancelReminder') && !!button.cancelReminder) {
|
|
510
|
+
return { name: 'cta_cancel_reminder', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'π Cancel reminder', id: button.id || button.cancelReminder, icon: buttonIcon }) };
|
|
511
|
+
}
|
|
512
|
+
else if (hasOptionalProperty(button, 'address') && !!button.address) {
|
|
513
|
+
return { name: 'address_message', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'π Send address', id: button.id || 'address_message' }) };
|
|
514
|
+
}
|
|
515
|
+
else if (hasOptionalProperty(button, 'location') && button.location === true) {
|
|
516
|
+
return { name: 'send_location', buttonParamsJson: JSON.stringify({}) };
|
|
517
|
+
}
|
|
518
|
+
else if (hasOptionalProperty(button, 'catalog') && !!button.catalog) {
|
|
519
|
+
return { name: 'catalog_message', buttonParamsJson: JSON.stringify({ business_phone_number: button.catalog.bizJid || button.catalog, display_text: buttonText || 'ποΈ View catalog', id: button.id || 'catalog_message' }) };
|
|
520
|
+
}
|
|
521
|
+
else if (hasOptionalProperty(button, 'products') && !!button.products) {
|
|
522
|
+
return { name: 'mpm', buttonParamsJson: JSON.stringify({ business_phone_number: button.bizJid || button.products.bizJid, product_ids: Array.isArray(button.products) ? button.products : button.products.ids }) };
|
|
523
|
+
}
|
|
524
|
+
else if (hasOptionalProperty(button, 'otp') && !!button.otp) {
|
|
525
|
+
return { name: 'otp_button', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Copy code', code: button.otp }) };
|
|
526
|
+
}
|
|
527
|
+
else if (hasOptionalProperty(button, 'oneTapOtp') && !!button.oneTapOtp) {
|
|
528
|
+
return { name: 'authentication_button', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'Autofill', code: button.oneTapOtp }) };
|
|
529
|
+
}
|
|
530
|
+
else if (hasOptionalProperty(button, 'phoneNumber') && !!button.phoneNumber) {
|
|
531
|
+
return { name: 'call_button', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'π Call', phone_number: button.phoneNumber }) };
|
|
532
|
+
}
|
|
533
|
+
else if (hasOptionalProperty(button, 'urlBtn') && !!button.urlBtn) {
|
|
534
|
+
return { name: 'url_button', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'π Open', url: button.urlBtn }) };
|
|
535
|
+
}
|
|
536
|
+
else if (hasOptionalProperty(button, 'card') && !!button.card) {
|
|
537
|
+
return { name: 'card_message', buttonParamsJson: JSON.stringify(button.card) };
|
|
538
|
+
}
|
|
539
|
+
else if (hasOptionalProperty(button, 'orderDetails') && !!button.orderDetails) {
|
|
540
|
+
return { name: 'order_details', buttonParamsJson: JSON.stringify(button.orderDetails) };
|
|
541
|
+
}
|
|
542
|
+
else if (hasOptionalProperty(button, 'orderStatus') && !!button.orderStatus) {
|
|
543
|
+
return { name: 'order_status', buttonParamsJson: JSON.stringify(button.orderStatus) };
|
|
544
|
+
}
|
|
545
|
+
else if (hasOptionalProperty(button, 'trackOrder') && !!button.trackOrder) {
|
|
546
|
+
return { name: 'track_order', buttonParamsJson: JSON.stringify({ id: button.id || button.trackOrder, display_text: buttonText || 'π Track order' }) };
|
|
547
|
+
}
|
|
548
|
+
else if (hasOptionalProperty(button, 'reorder') && !!button.reorder) {
|
|
549
|
+
return { name: 'reorder', buttonParamsJson: JSON.stringify({ id: button.id || button.reorder, display_text: buttonText || 'π Reorder' }) };
|
|
550
|
+
}
|
|
551
|
+
else if (hasOptionalProperty(button, 'cancelOrder') && !!button.cancelOrder) {
|
|
552
|
+
return { name: 'cancel_order', buttonParamsJson: JSON.stringify({ id: button.id || button.cancelOrder, display_text: buttonText || 'β Cancel order' }) };
|
|
553
|
+
}
|
|
554
|
+
else if (hasOptionalProperty(button, 'clearChat') && button.clearChat === true) {
|
|
555
|
+
return { name: 'clear_chat', buttonParamsJson: JSON.stringify({}) };
|
|
556
|
+
}
|
|
557
|
+
else if (hasOptionalProperty(button, 'screen') && !!button.screen) {
|
|
558
|
+
return { name: 'navigateToScreen', buttonParamsJson: JSON.stringify({ screen_name: button.screen, data: button.data || {} }) };
|
|
559
|
+
}
|
|
560
|
+
else if (hasOptionalProperty(button, 'flow') && !!button.flow) {
|
|
561
|
+
return { name: 'flow_action', buttonParamsJson: JSON.stringify({ flow_message_version: button.flow.version || '3', flow_id: button.flow.id, flow_cta: buttonText || button.flow.cta || 'Continue', flow_action: button.flow.action || 'navigate', flow_action_payload: button.flow.actionPayload || { screen: button.flow.screen || 'WELCOME', data: button.flow.data || {} } }) };
|
|
562
|
+
}
|
|
563
|
+
else if (hasOptionalProperty(button, 'voiceCall') && !!button.voiceCall) {
|
|
564
|
+
return { name: 'voice_call', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'π Voice call', id: button.id || button.voiceCall }) };
|
|
565
|
+
}
|
|
566
|
+
else if (hasOptionalProperty(button, 'videoCall') && !!button.videoCall) {
|
|
567
|
+
return { name: 'video_call_button', buttonParamsJson: JSON.stringify({ display_text: buttonText || 'π₯ Video call', id: button.id || button.videoCall }) };
|
|
568
|
+
}
|
|
475
569
|
return button;
|
|
476
570
|
}),
|
|
477
571
|
messageParamsJson: JSON.stringify(messageParamsJson)
|
|
@@ -936,7 +1030,12 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
936
1030
|
const key = m[messageType];
|
|
937
1031
|
if (key && 'contextInfo' in key && !!key.contextInfo) key.contextInfo.isGroupStatus = message.groupStatus;
|
|
938
1032
|
else if (key) key.contextInfo = { isGroupStatus: message.groupStatus };
|
|
939
|
-
|
|
1033
|
+
// Fix: audio PTT usa groupStatusMessage (v1) β V2 causa tela preta em versΓ΅es antigas do WA
|
|
1034
|
+
if (messageType === 'audioMessage') {
|
|
1035
|
+
m = { groupStatusMessage: { message: m } };
|
|
1036
|
+
} else {
|
|
1037
|
+
m = { groupStatusMessageV2: { message: m } };
|
|
1038
|
+
}
|
|
940
1039
|
delete message.groupStatus;
|
|
941
1040
|
}
|
|
942
1041
|
// ββ spoiler βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -961,6 +1060,12 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
961
1060
|
}
|
|
962
1061
|
// ββ isLottie ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
963
1062
|
if (hasOptionalProperty(message, 'isLottie') && !!message.isLottie) {
|
|
1063
|
+
// marca o stickerMessage interno com isLottie: true para o WA renderizar como premium
|
|
1064
|
+
if (m.stickerMessage) {
|
|
1065
|
+
m.stickerMessage.isLottie = true;
|
|
1066
|
+
m.stickerMessage.isAnimated = m.stickerMessage.isAnimated ?? false;
|
|
1067
|
+
m.stickerMessage.isAiSticker = false;
|
|
1068
|
+
}
|
|
964
1069
|
m = { lottieStickerMessage: { message: m } };
|
|
965
1070
|
}
|
|
966
1071
|
// ββ viewOnceV2 / viewOnceV2Extension ββββββββββββββββββββββββββββββββββββββ
|
|
@@ -1094,7 +1199,8 @@ export const normalizeMessageContent = (content) => {
|
|
|
1094
1199
|
message?.documentWithCaptionMessage ||
|
|
1095
1200
|
message?.viewOnceMessageV2 ||
|
|
1096
1201
|
message?.viewOnceMessageV2Extension ||
|
|
1097
|
-
message?.editedMessage
|
|
1202
|
+
message?.editedMessage ||
|
|
1203
|
+
message?.lottieStickerMessage);
|
|
1098
1204
|
}
|
|
1099
1205
|
};
|
|
1100
1206
|
export const extractMessageContent = (content) => {
|