@itsliaaa/baileys 0.1.5 → 0.1.7
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/WAProto/index.js +502 -58
- package/lib/Socket/messages-recv.js +88 -130
- package/lib/Utils/index.js +2 -1
- package/lib/Utils/offline-node-processor.js +39 -0
- package/lib/Utils/stanza-ack.js +37 -0
- package/lib/WABinary/generic-utils.js +8 -8
- package/package.json +2 -2
|
@@ -7,6 +7,8 @@ import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT, PLACEHOLDER_MAX_
|
|
|
7
7
|
import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
|
|
8
8
|
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, extractAddressingContext, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, handleIdentityChange, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, toNumber, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
|
|
9
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
10
|
+
import { makeOfflineNodeProcessor } from '../Utils/offline-node-processor.js';
|
|
11
|
+
import { buildAckStanza } from '../Utils/stanza-ack.js';
|
|
10
12
|
import { areJidsSameUser, binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
13
|
import { extractGroupMetadata } from './groups.js';
|
|
12
14
|
import { makeMessagesSocket } from './messages-send.js';
|
|
@@ -217,32 +219,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
217
219
|
break;
|
|
218
220
|
}
|
|
219
221
|
};
|
|
220
|
-
const sendMessageAck = async (
|
|
221
|
-
const stanza =
|
|
222
|
-
|
|
223
|
-
attrs: {
|
|
224
|
-
id: attrs.id,
|
|
225
|
-
to: attrs.from,
|
|
226
|
-
class: tag
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
if (!!errorCode) {
|
|
230
|
-
stanza.attrs.error = errorCode.toString();
|
|
231
|
-
}
|
|
232
|
-
if (!!attrs.participant) {
|
|
233
|
-
stanza.attrs.participant = attrs.participant;
|
|
234
|
-
}
|
|
235
|
-
if (!!attrs.recipient) {
|
|
236
|
-
stanza.attrs.recipient = attrs.recipient;
|
|
237
|
-
}
|
|
238
|
-
if (!!attrs.type &&
|
|
239
|
-
(tag !== 'message' || getBinaryNodeChild({ tag, attrs, content }, 'unavailable') || errorCode !== 0)) {
|
|
240
|
-
stanza.attrs.type = attrs.type;
|
|
241
|
-
}
|
|
242
|
-
if (tag === 'message' && getBinaryNodeChild({ tag, attrs, content }, 'unavailable')) {
|
|
243
|
-
stanza.attrs.from = authState.creds.me.id;
|
|
244
|
-
}
|
|
245
|
-
logger.debug({ recv: { tag, attrs }, sent: stanza.attrs }, 'sent ack');
|
|
222
|
+
const sendMessageAck = async (node, errorCode) => {
|
|
223
|
+
const stanza = buildAckStanza(node, errorCode, authState.creds.me.id);
|
|
224
|
+
logger.debug({ recv: { tag: node.tag, attrs: node.attrs }, sent: stanza.attrs }, 'sent ack');
|
|
246
225
|
await sendNode(stanza);
|
|
247
226
|
};
|
|
248
227
|
const rejectCall = async (callId, callFrom) => {
|
|
@@ -995,7 +974,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
995
974
|
]);
|
|
996
975
|
}
|
|
997
976
|
finally {
|
|
998
|
-
await sendMessageAck(node);
|
|
977
|
+
await sendMessageAck(node).catch(ackErr => logger.error({ ackErr }, 'failed to ack receipt'));
|
|
999
978
|
}
|
|
1000
979
|
};
|
|
1001
980
|
const handleNotification = async (node) => {
|
|
@@ -1030,7 +1009,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1030
1009
|
]);
|
|
1031
1010
|
}
|
|
1032
1011
|
finally {
|
|
1033
|
-
await sendMessageAck(node);
|
|
1012
|
+
await sendMessageAck(node).catch(ackErr => logger.error({ ackErr }, 'failed to ack notification'));
|
|
1034
1013
|
}
|
|
1035
1014
|
};
|
|
1036
1015
|
const handleMessage = async (node) => {
|
|
@@ -1046,36 +1025,34 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1046
1025
|
await sendMessageAck(node, NACK_REASONS.MissingMessageSecret);
|
|
1047
1026
|
return;
|
|
1048
1027
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
await signalRepository.
|
|
1028
|
+
let acked = false;
|
|
1029
|
+
try {
|
|
1030
|
+
const { fullMessage: msg, category, author, decrypt } = decryptMessageNode(node, authState.creds.me.id, authState.creds.me.lid || '', signalRepository, logger);
|
|
1031
|
+
const alt = msg.key.participantAlt || msg.key.remoteJidAlt;
|
|
1032
|
+
// store new mappings we didn't have before
|
|
1033
|
+
if (!!alt) {
|
|
1034
|
+
const altServer = jidDecode(alt)?.server;
|
|
1035
|
+
const primaryJid = msg.key.participant || msg.key.remoteJid;
|
|
1036
|
+
if (altServer === 'lid') {
|
|
1037
|
+
if (!(await signalRepository.lidMapping.getPNForLID(alt))) {
|
|
1038
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: alt, pn: primaryJid }]);
|
|
1039
|
+
await signalRepository.migrateSession(primaryJid, alt);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
else {
|
|
1043
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: primaryJid, pn: alt }]);
|
|
1044
|
+
await signalRepository.migrateSession(alt, primaryJid);
|
|
1059
1045
|
}
|
|
1060
1046
|
}
|
|
1061
|
-
else {
|
|
1062
|
-
await signalRepository.lidMapping.storeLIDPNMappings([{ lid: primaryJid, pn: alt }]);
|
|
1063
|
-
await signalRepository.migrateSession(alt, primaryJid);
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
if (msg.key?.remoteJid && msg.key?.id && messageRetryManager) {
|
|
1067
|
-
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
1068
|
-
logger.debug({
|
|
1069
|
-
jid: msg.key.remoteJid,
|
|
1070
|
-
id: msg.key.id
|
|
1071
|
-
}, 'Added message to recent cache for retry receipts');
|
|
1072
|
-
}
|
|
1073
|
-
try {
|
|
1074
1047
|
await messageMutex.mutex(async () => {
|
|
1075
1048
|
await decrypt();
|
|
1049
|
+
if (msg.key?.remoteJid && msg.key?.id && msg.message && messageRetryManager) {
|
|
1050
|
+
messageRetryManager.addRecentMessage(msg.key.remoteJid, msg.key.id, msg.message);
|
|
1051
|
+
}
|
|
1076
1052
|
// message failed to decrypt
|
|
1077
1053
|
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT && msg.category !== 'peer') {
|
|
1078
1054
|
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
1055
|
+
acked = true;
|
|
1079
1056
|
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
1080
1057
|
}
|
|
1081
1058
|
if (msg.messageStubParameters?.[0] === NO_MESSAGE_FOUND_ERROR_TEXT) {
|
|
@@ -1087,11 +1064,13 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1087
1064
|
unavailableType === 'hosted_unavailable_fanout' ||
|
|
1088
1065
|
unavailableType === 'view_once_unavailable_fanout') {
|
|
1089
1066
|
logger.debug({ msgId: msg.key.id, unavailableType }, 'skipping placeholder resend for excluded unavailable type');
|
|
1067
|
+
acked = true;
|
|
1090
1068
|
return sendMessageAck(node);
|
|
1091
1069
|
}
|
|
1092
1070
|
const messageAge = unixTimestampSeconds() - toNumber(msg.messageTimestamp);
|
|
1093
1071
|
if (messageAge > PLACEHOLDER_MAX_AGE_SECONDS) {
|
|
1094
1072
|
logger.debug({ msgId: msg.key.id, messageAge }, 'skipping placeholder resend for old message');
|
|
1073
|
+
acked = true;
|
|
1095
1074
|
return sendMessageAck(node);
|
|
1096
1075
|
}
|
|
1097
1076
|
// Request the real content from the phone via placeholder resend PDO.
|
|
@@ -1128,6 +1107,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1128
1107
|
.catch(err => {
|
|
1129
1108
|
logger.warn({ err, msgId: msg.key.id }, 'failed to request placeholder resend for unavailable message');
|
|
1130
1109
|
});
|
|
1110
|
+
acked = true;
|
|
1131
1111
|
await sendMessageAck(node);
|
|
1132
1112
|
// Don't return — fall through to upsertMessage so the stub is emitted
|
|
1133
1113
|
}
|
|
@@ -1137,6 +1117,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1137
1117
|
const messageAge = unixTimestampSeconds() - toNumber(msg.messageTimestamp);
|
|
1138
1118
|
if (messageAge > STATUS_EXPIRY_SECONDS) {
|
|
1139
1119
|
logger.debug({ msgId: msg.key.id, messageAge, remoteJid: msg.key.remoteJid }, 'skipping retry for expired status message');
|
|
1120
|
+
acked = true;
|
|
1140
1121
|
return sendMessageAck(node);
|
|
1141
1122
|
}
|
|
1142
1123
|
}
|
|
@@ -1180,6 +1161,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1180
1161
|
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
1181
1162
|
}
|
|
1182
1163
|
}
|
|
1164
|
+
acked = true;
|
|
1183
1165
|
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
1184
1166
|
});
|
|
1185
1167
|
}
|
|
@@ -1208,6 +1190,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1208
1190
|
else if (!sendActiveReceipts) {
|
|
1209
1191
|
type = 'inactive';
|
|
1210
1192
|
}
|
|
1193
|
+
acked = true;
|
|
1211
1194
|
await sendReceipt(msg.key.remoteJid, participant, [msg.key.id], type);
|
|
1212
1195
|
// send ack for history message
|
|
1213
1196
|
const isAnyHistoryMsg = getHistoryMsg(msg.message);
|
|
@@ -1217,6 +1200,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1217
1200
|
}
|
|
1218
1201
|
}
|
|
1219
1202
|
else {
|
|
1203
|
+
acked = true;
|
|
1220
1204
|
await sendMessageAck(node);
|
|
1221
1205
|
logger.debug({ key: msg.key }, 'processed newsletter message without receipts');
|
|
1222
1206
|
}
|
|
@@ -1227,45 +1211,55 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1227
1211
|
}
|
|
1228
1212
|
catch (error) {
|
|
1229
1213
|
logger.error({ error, node: binaryNodeToString(node) }, 'error in handling message');
|
|
1214
|
+
if (!acked) {
|
|
1215
|
+
await sendMessageAck(node, NACK_REASONS.UnhandledError).catch(ackErr => logger.error({ ackErr }, 'failed to ack message after error'));
|
|
1216
|
+
}
|
|
1230
1217
|
}
|
|
1231
1218
|
};
|
|
1232
1219
|
const handleCall = async (node) => {
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1220
|
+
try {
|
|
1221
|
+
const { attrs } = node;
|
|
1222
|
+
const [infoChild] = getAllBinaryNodeChildren(node);
|
|
1223
|
+
if (!infoChild) {
|
|
1224
|
+
throw new Boom('Missing call info in call node');
|
|
1225
|
+
}
|
|
1226
|
+
const status = getCallStatusFromNode(infoChild);
|
|
1227
|
+
const callId = infoChild.attrs['call-id'];
|
|
1228
|
+
const from = infoChild.attrs.from || infoChild.attrs['call-creator'];
|
|
1229
|
+
const call = {
|
|
1230
|
+
chatId: attrs.from,
|
|
1231
|
+
from,
|
|
1232
|
+
callerPn: infoChild.attrs['caller_pn'],
|
|
1233
|
+
id: callId,
|
|
1234
|
+
date: new Date(+attrs.t * 1000),
|
|
1235
|
+
offline: !!attrs.offline,
|
|
1236
|
+
status
|
|
1237
|
+
};
|
|
1238
|
+
if (status === 'offer') {
|
|
1239
|
+
call.isVideo = !!getBinaryNodeChild(infoChild, 'video');
|
|
1240
|
+
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid'];
|
|
1241
|
+
call.groupJid = infoChild.attrs['group-jid'];
|
|
1242
|
+
await callOfferCache.set(call.id, call);
|
|
1243
|
+
}
|
|
1244
|
+
const existingCall = await callOfferCache.get(call.id);
|
|
1245
|
+
// use existing call info to populate this event
|
|
1246
|
+
if (existingCall) {
|
|
1247
|
+
call.isVideo = existingCall.isVideo;
|
|
1248
|
+
call.isGroup = existingCall.isGroup;
|
|
1249
|
+
call.callerPn = call.callerPn || existingCall.callerPn;
|
|
1250
|
+
}
|
|
1251
|
+
// delete data once call has ended
|
|
1252
|
+
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
1253
|
+
await callOfferCache.del(call.id);
|
|
1254
|
+
}
|
|
1255
|
+
ev.emit('call', [call]);
|
|
1255
1256
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
if (existingCall) {
|
|
1259
|
-
call.isVideo = existingCall.isVideo;
|
|
1260
|
-
call.isGroup = existingCall.isGroup;
|
|
1261
|
-
call.callerPn = call.callerPn || existingCall.callerPn;
|
|
1257
|
+
catch (error) {
|
|
1258
|
+
logger.error({ error, node: binaryNodeToString(node) }, 'error in handling call');
|
|
1262
1259
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
await callOfferCache.del(call.id);
|
|
1260
|
+
finally {
|
|
1261
|
+
await sendMessageAck(node).catch(ackErr => logger.error({ ackErr }, 'failed to ack call'));
|
|
1266
1262
|
}
|
|
1267
|
-
ev.emit('call', [call]);
|
|
1268
|
-
await sendMessageAck(node);
|
|
1269
1263
|
};
|
|
1270
1264
|
const handleBadAck = async ({ attrs }) => {
|
|
1271
1265
|
const key = { remoteJid: attrs.from, fromMe: true, id: attrs.id };
|
|
@@ -1320,52 +1314,16 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1320
1314
|
return exec(node, false).catch(err => onUnexpectedError(err, identifier));
|
|
1321
1315
|
}
|
|
1322
1316
|
};
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
]);
|
|
1334
|
-
const nodes = [];
|
|
1335
|
-
let isProcessing = false;
|
|
1336
|
-
// Number of nodes to process before yielding to event loop
|
|
1337
|
-
const BATCH_SIZE = 10;
|
|
1338
|
-
const enqueue = (type, node) => {
|
|
1339
|
-
nodes.push({ type, node });
|
|
1340
|
-
if (isProcessing) {
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
isProcessing = true;
|
|
1344
|
-
const promise = async () => {
|
|
1345
|
-
let processedInBatch = 0;
|
|
1346
|
-
while (nodes.length && ws.isOpen) {
|
|
1347
|
-
const { type, node } = nodes.shift();
|
|
1348
|
-
const nodeProcessor = nodeProcessorMap.get(type);
|
|
1349
|
-
if (!nodeProcessor) {
|
|
1350
|
-
onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node');
|
|
1351
|
-
continue;
|
|
1352
|
-
}
|
|
1353
|
-
await nodeProcessor(node);
|
|
1354
|
-
processedInBatch++;
|
|
1355
|
-
// Yield to event loop after processing a batch
|
|
1356
|
-
// This prevents blocking the event loop for too long when there are many offline nodes
|
|
1357
|
-
if (processedInBatch >= BATCH_SIZE) {
|
|
1358
|
-
processedInBatch = 0;
|
|
1359
|
-
await yieldToEventLoop();
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
isProcessing = false;
|
|
1363
|
-
};
|
|
1364
|
-
promise().catch(error => onUnexpectedError(error, 'processing offline nodes'));
|
|
1365
|
-
};
|
|
1366
|
-
return { enqueue };
|
|
1367
|
-
};
|
|
1368
|
-
const offlineNodeProcessor = makeOfflineNodeProcessor();
|
|
1317
|
+
const offlineNodeProcessor = makeOfflineNodeProcessor(new Map([
|
|
1318
|
+
['message', handleMessage],
|
|
1319
|
+
['call', handleCall],
|
|
1320
|
+
['receipt', handleReceipt],
|
|
1321
|
+
['notification', handleNotification]
|
|
1322
|
+
]), {
|
|
1323
|
+
isWsOpen: () => ws.isOpen,
|
|
1324
|
+
onUnexpectedError,
|
|
1325
|
+
yieldToEventLoop: () => new Promise(resolve => setImmediate(resolve))
|
|
1326
|
+
});
|
|
1369
1327
|
const processNode = async (type, node, identifier, exec) => {
|
|
1370
1328
|
const isOffline = !!node.attrs.offline;
|
|
1371
1329
|
if (isOffline) {
|
package/lib/Utils/index.js
CHANGED
|
@@ -16,4 +16,5 @@ 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 './identity-change-handler.js';
|
|
19
|
+
export * from './identity-change-handler.js';
|
|
20
|
+
export * from './stanza-ack.js';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a processor for offline stanza nodes that:
|
|
3
|
+
* - Queues nodes for sequential processing
|
|
4
|
+
* - Yields to the event loop periodically to avoid blocking
|
|
5
|
+
* - Catches handler errors to prevent the processing loop from crashing
|
|
6
|
+
*/
|
|
7
|
+
export function makeOfflineNodeProcessor(nodeProcessorMap, deps, batchSize = 10) {
|
|
8
|
+
const nodes = [];
|
|
9
|
+
let isProcessing = false;
|
|
10
|
+
const enqueue = (type, node) => {
|
|
11
|
+
nodes.push({ type, node });
|
|
12
|
+
if (isProcessing) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
isProcessing = true;
|
|
16
|
+
const promise = async () => {
|
|
17
|
+
let processedInBatch = 0;
|
|
18
|
+
while (nodes.length && deps.isWsOpen()) {
|
|
19
|
+
const { type, node } = nodes.shift();
|
|
20
|
+
const nodeProcessor = nodeProcessorMap.get(type);
|
|
21
|
+
if (!nodeProcessor) {
|
|
22
|
+
deps.onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node');
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
await nodeProcessor(node).catch(err => deps.onUnexpectedError(err, `processing offline ${type}`));
|
|
26
|
+
processedInBatch++;
|
|
27
|
+
// Yield to event loop after processing a batch
|
|
28
|
+
// This prevents blocking the event loop for too long when there are many offline nodes
|
|
29
|
+
if (processedInBatch >= batchSize) {
|
|
30
|
+
processedInBatch = 0;
|
|
31
|
+
await deps.yieldToEventLoop();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
isProcessing = false;
|
|
35
|
+
};
|
|
36
|
+
promise().catch(error => deps.onUnexpectedError(error, 'processing offline nodes'));
|
|
37
|
+
};
|
|
38
|
+
return { enqueue };
|
|
39
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an ACK stanza for a received node.
|
|
3
|
+
* Pure function -- no I/O, no side effects.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors WhatsApp Web's ACK construction:
|
|
6
|
+
* - WAWebHandleMsgSendAck.sendAck / sendNack
|
|
7
|
+
* - WAWebCreateNackFromStanza.createNackFromStanza
|
|
8
|
+
*/
|
|
9
|
+
export function buildAckStanza(node, errorCode, meId) {
|
|
10
|
+
const { tag, attrs } = node;
|
|
11
|
+
const stanza = {
|
|
12
|
+
tag: 'ack',
|
|
13
|
+
attrs: {
|
|
14
|
+
id: attrs.id,
|
|
15
|
+
to: attrs.from,
|
|
16
|
+
class: tag
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
if (errorCode) {
|
|
20
|
+
stanza.attrs.error = errorCode.toString();
|
|
21
|
+
}
|
|
22
|
+
if (attrs.participant) {
|
|
23
|
+
stanza.attrs.participant = attrs.participant;
|
|
24
|
+
}
|
|
25
|
+
if (attrs.recipient) {
|
|
26
|
+
stanza.attrs.recipient = attrs.recipient;
|
|
27
|
+
}
|
|
28
|
+
// WA Web always includes type when present: `n.type || DROP_ATTR`
|
|
29
|
+
if (attrs.type) {
|
|
30
|
+
stanza.attrs.type = attrs.type;
|
|
31
|
+
}
|
|
32
|
+
// WA Web WAWebHandleMsgSendAck.sendAck/sendNack always include `from` for message-class ACKs
|
|
33
|
+
if (tag === 'message' && meId) {
|
|
34
|
+
stanza.attrs.from = meId;
|
|
35
|
+
}
|
|
36
|
+
return stanza;
|
|
37
|
+
}
|
|
@@ -124,12 +124,12 @@ export function binaryNodeToString(node, i = 0) {
|
|
|
124
124
|
* @returns {object} A node with shape { tag, attrs, [content] } to inject into additionalNodes.
|
|
125
125
|
*/
|
|
126
126
|
const FLOWS_MAP = {
|
|
127
|
-
mpm:
|
|
128
|
-
cta_catalog:
|
|
129
|
-
send_location:
|
|
130
|
-
call_permission_request:
|
|
131
|
-
wa_payment_transaction_details:
|
|
132
|
-
automated_greeting_message_view_catalog:
|
|
127
|
+
mpm: true,
|
|
128
|
+
cta_catalog: true,
|
|
129
|
+
send_location: true,
|
|
130
|
+
call_permission_request: true,
|
|
131
|
+
wa_payment_transaction_details: true,
|
|
132
|
+
automated_greeting_message_view_catalog: true
|
|
133
133
|
};
|
|
134
134
|
const qualityAttribute = {
|
|
135
135
|
tag: 'quality_control',
|
|
@@ -157,7 +157,7 @@ export const getBizBinaryNode = (message) => {
|
|
|
157
157
|
content: defaultContent
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
|
-
|
|
160
|
+
if (buttonName && FLOWS_MAP[buttonName]) {
|
|
161
161
|
return {
|
|
162
162
|
tag: 'biz',
|
|
163
163
|
attrs: {},
|
|
@@ -195,7 +195,7 @@ export const getBizBinaryNode = (message) => {
|
|
|
195
195
|
]
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
|
-
|
|
198
|
+
if (message.listMessage) {
|
|
199
199
|
return {
|
|
200
200
|
tag: 'biz',
|
|
201
201
|
attrs: {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itsliaaa/baileys",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "A simple fork of Baileys for WhatsApp automation",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"p-queue": "^9.1.0",
|
|
49
49
|
"pino": "^9.6.0",
|
|
50
50
|
"protobufjs": "^7.5.4",
|
|
51
|
-
"whatsapp-rust-bridge": "
|
|
51
|
+
"whatsapp-rust-bridge": "0.5.3",
|
|
52
52
|
"ws": "^8.19.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|