@crysnovax/baileys 2.6.3 → 2.6.4
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 +19 -0
- package/lib/Socket/messages-send.js +134 -1
- package/lib/Socket/messages-send.js[old] +30 -0
- package/lib/Utils/messages.js +38 -0
- package/lib/Utils/messages.js[old] +1864 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -721,7 +721,26 @@ sock.sendMessage(jid, {
|
|
|
721
721
|
]
|
|
722
722
|
})
|
|
723
723
|
```
|
|
724
|
+
### Rich preview
|
|
725
|
+
```
|
|
726
|
+
await sock.sendMessage(jid, {
|
|
727
|
+
text: 'https://chat.whatsapp.com/CODE',
|
|
728
|
+
richPreview: true,
|
|
729
|
+
previewTitle: 'My Group',
|
|
730
|
+
previewDescription: '42 members · Tap to join',
|
|
731
|
+
previewImage: imageBufferOrUrl // Buffer, or a URL string
|
|
732
|
+
})
|
|
733
|
+
```
|
|
724
734
|
|
|
735
|
+
### WHATSAPP VERIFIED ☑️ ⚉
|
|
736
|
+
send Media messages with verified WhatsApp check ✔️
|
|
737
|
+
```
|
|
738
|
+
await sock.sendMessage(jid, {
|
|
739
|
+
image: buffer,
|
|
740
|
+
caption: 'Hello',
|
|
741
|
+
verifiedMe: true
|
|
742
|
+
})
|
|
743
|
+
```
|
|
725
744
|
---
|
|
726
745
|
|
|
727
746
|
## Meta AI Features
|
|
@@ -3,7 +3,7 @@ import { Boom } from '@hapi/boom';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { proto } from '../../WAProto/index.js';
|
|
5
5
|
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
|
-
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
6
|
+
import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
7
|
import { AssociationType } from '../Types/index.js';
|
|
8
8
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
9
9
|
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
|
|
@@ -1248,6 +1248,139 @@ export const makeMessagesSocket = (config) => {
|
|
|
1248
1248
|
}
|
|
1249
1249
|
return fullMsg;
|
|
1250
1250
|
}
|
|
1251
|
+
// crysnovax@RichPreview --- richPreview:true auto-builds a manually-constructed
|
|
1252
|
+
// extendedTextMessage with a large preview image, bypassing generateWAMessage's
|
|
1253
|
+
// getUrlInfo scraper (which fails on bot-blocked domains like chat.whatsapp.com)
|
|
1254
|
+
// and avoiding the undocumented ~7KB jpegThumbnail size ceiling that causes a
|
|
1255
|
+
// blank/black render on WA clients when exceeded.
|
|
1256
|
+
//
|
|
1257
|
+
// Usage:
|
|
1258
|
+
// sock.sendMessage(jid, {
|
|
1259
|
+
// text: 'https://chat.whatsapp.com/CODE',
|
|
1260
|
+
// richPreview: true,
|
|
1261
|
+
// previewTitle: 'Group Name',
|
|
1262
|
+
// previewDescription: '12 members · Tap to join',
|
|
1263
|
+
// previewImage: imageBufferOrUrl // Buffer, or a URL string to fetch
|
|
1264
|
+
// })
|
|
1265
|
+
else if ('richPreview' in content && content.richPreview === true) {
|
|
1266
|
+
const {
|
|
1267
|
+
richPreview: __rp,
|
|
1268
|
+
text: previewLink,
|
|
1269
|
+
previewTitle,
|
|
1270
|
+
previewDescription,
|
|
1271
|
+
previewImage,
|
|
1272
|
+
quoted,
|
|
1273
|
+
...restContent
|
|
1274
|
+
} = content;
|
|
1275
|
+
|
|
1276
|
+
if (!previewLink || typeof previewLink !== 'string') {
|
|
1277
|
+
throw new Boom('richPreview requires a `text` field containing the URL', { statusCode: 400 });
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// Resolve previewImage into a raw Buffer, whether given as
|
|
1281
|
+
// a Buffer directly or a URL string to fetch
|
|
1282
|
+
let imageBuffer = null;
|
|
1283
|
+
if (previewImage) {
|
|
1284
|
+
if (Buffer.isBuffer(previewImage)) {
|
|
1285
|
+
imageBuffer = previewImage;
|
|
1286
|
+
}
|
|
1287
|
+
else if (typeof previewImage === 'string') {
|
|
1288
|
+
try {
|
|
1289
|
+
const res = await fetch(previewImage);
|
|
1290
|
+
imageBuffer = Buffer.from(await res.arrayBuffer());
|
|
1291
|
+
}
|
|
1292
|
+
catch (err) {
|
|
1293
|
+
logger?.warn({ err }, 'richPreview: failed to fetch previewImage URL');
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Small embedded jpegThumbnail — kept under the ~7KB ceiling
|
|
1299
|
+
// that causes WA clients to render a blank/black preview if exceeded.
|
|
1300
|
+
// 296px @ quality 50 (fixed internally by extractImageThumb) sits
|
|
1301
|
+
// safely under that threshold while staying as sharp as reliably possible.
|
|
1302
|
+
let smallThumb = null;
|
|
1303
|
+
if (imageBuffer) {
|
|
1304
|
+
try {
|
|
1305
|
+
const { buffer } = await extractImageThumb(imageBuffer, 296);
|
|
1306
|
+
smallThumb = buffer;
|
|
1307
|
+
}
|
|
1308
|
+
catch (err) {
|
|
1309
|
+
logger?.warn({ err }, 'richPreview: failed to generate small thumbnail');
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// Upload the image through the real media pipeline to get a
|
|
1314
|
+
// proper highQualityThumbnail reference (directPath/mediaKey/etc)
|
|
1315
|
+
let hq = null;
|
|
1316
|
+
if (imageBuffer) {
|
|
1317
|
+
try {
|
|
1318
|
+
const prepared = await prepareWAMessageMedia({ image: imageBuffer }, { upload: waUploadToServer });
|
|
1319
|
+
hq = prepared.imageMessage;
|
|
1320
|
+
}
|
|
1321
|
+
catch (err) {
|
|
1322
|
+
logger?.warn({ err }, 'richPreview: failed to upload HQ thumbnail');
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
const previewMessage = {
|
|
1327
|
+
extendedTextMessage: {
|
|
1328
|
+
text: previewLink,
|
|
1329
|
+
matchedText: previewLink,
|
|
1330
|
+
canonicalUrl: previewLink,
|
|
1331
|
+
title: previewTitle || '',
|
|
1332
|
+
description: previewDescription || '',
|
|
1333
|
+
previewType: 5, // IMAGE
|
|
1334
|
+
jpegThumbnail: smallThumb || undefined,
|
|
1335
|
+
...(hq
|
|
1336
|
+
? {
|
|
1337
|
+
thumbnailDirectPath: hq.directPath,
|
|
1338
|
+
mediaKey: hq.mediaKey,
|
|
1339
|
+
mediaKeyTimestamp: hq.mediaKeyTimestamp,
|
|
1340
|
+
thumbnailWidth: hq.width,
|
|
1341
|
+
thumbnailHeight: hq.height,
|
|
1342
|
+
thumbnailSha256: hq.fileSha256,
|
|
1343
|
+
thumbnailEncSha256: hq.fileEncSha256
|
|
1344
|
+
}
|
|
1345
|
+
: {}),
|
|
1346
|
+
...restContent
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
const msgId = options.messageId || generateMessageIDV2(userJid);
|
|
1351
|
+
|
|
1352
|
+
if (quoted) {
|
|
1353
|
+
previewMessage.extendedTextMessage.contextInfo = {
|
|
1354
|
+
...(previewMessage.extendedTextMessage.contextInfo || {}),
|
|
1355
|
+
stanzaId: quoted.key.id,
|
|
1356
|
+
participant: jidNormalizedUser(quoted.key.fromMe ? userJid : (quoted.key.participant || quoted.key.remoteJid)),
|
|
1357
|
+
quotedMessage: quoted.message
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
await relayMessage(jid, previewMessage, {
|
|
1362
|
+
messageId: msgId,
|
|
1363
|
+
additionalAttributes: options.additionalAttributes || {},
|
|
1364
|
+
additionalNodes: options.additionalNodes || []
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
const fullMsg = {
|
|
1368
|
+
key: {
|
|
1369
|
+
remoteJid: jid,
|
|
1370
|
+
fromMe: true,
|
|
1371
|
+
id: msgId
|
|
1372
|
+
},
|
|
1373
|
+
message: previewMessage,
|
|
1374
|
+
messageTimestamp: unixTimestampSeconds()
|
|
1375
|
+
};
|
|
1376
|
+
|
|
1377
|
+
if (config.emitOwnEvents) {
|
|
1378
|
+
process.nextTick(async () => {
|
|
1379
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
return fullMsg;
|
|
1383
|
+
}
|
|
1251
1384
|
else {
|
|
1252
1385
|
const fullMsg = await generateWAMessage(jid, content, {
|
|
1253
1386
|
logger,
|
|
@@ -1218,6 +1218,36 @@ export const makeMessagesSocket = (config) => {
|
|
|
1218
1218
|
: disappearingMessagesInChat;
|
|
1219
1219
|
await groupToggleEphemeral(jid, value);
|
|
1220
1220
|
}
|
|
1221
|
+
// crysnovax@Status --- status:true flag routes any message type to status@broadcast
|
|
1222
|
+
// Supports: text with backgroundColor + font, image, video, audio, sticker
|
|
1223
|
+
// Usage: sock.sendMessage(jid, { text: 'Hello', status: true, backgroundColor: '#FF0000', font: 2 })
|
|
1224
|
+
// sock.sendMessage(jid, { audio: buffer, status: true, ptt: false })
|
|
1225
|
+
else if ('status' in content && content.status === true) {
|
|
1226
|
+
const { status: _, backgroundColor, font, statusJidList: contentJidList, ...statusContent } = content;
|
|
1227
|
+
const fullMsg = await generateWAMessage('status@broadcast', statusContent, {
|
|
1228
|
+
logger,
|
|
1229
|
+
userJid,
|
|
1230
|
+
upload: waUploadToServer,
|
|
1231
|
+
mediaCache: config.mediaCache,
|
|
1232
|
+
options: config.options,
|
|
1233
|
+
...options,
|
|
1234
|
+
...(backgroundColor ? { backgroundColor } : {}),
|
|
1235
|
+
...(font !== undefined ? { font } : {}),
|
|
1236
|
+
messageId: generateMessageIDV2(userJid)
|
|
1237
|
+
});
|
|
1238
|
+
await relayMessage('status@broadcast', fullMsg.message, {
|
|
1239
|
+
messageId: fullMsg.key.id,
|
|
1240
|
+
statusJidList: contentJidList || options.statusJidList,
|
|
1241
|
+
additionalAttributes: options.additionalAttributes || {},
|
|
1242
|
+
additionalNodes: options.additionalNodes || []
|
|
1243
|
+
});
|
|
1244
|
+
if (config.emitOwnEvents) {
|
|
1245
|
+
process.nextTick(async () => {
|
|
1246
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
return fullMsg;
|
|
1250
|
+
}
|
|
1221
1251
|
else {
|
|
1222
1252
|
const fullMsg = await generateWAMessage(jid, content, {
|
|
1223
1253
|
logger,
|
package/lib/Utils/messages.js
CHANGED
|
@@ -1363,6 +1363,44 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1363
1363
|
m = { spoilerMessage: { message: m } };
|
|
1364
1364
|
delete message.spoiler;
|
|
1365
1365
|
}
|
|
1366
|
+
// crysnovax@VerifiedMe --- Add "verifiedMe" boolean to attach a verified
|
|
1367
|
+
// forward badge (✓) on image/video messages only. Uses forwardingScore +
|
|
1368
|
+
// isForwarded + the 0@s.whatsapp.net participant/remoteJid trick (no
|
|
1369
|
+
// newsletter context needed) — confirmed working pattern. Also injects a
|
|
1370
|
+
// synthetic quoted message fallback if none is already present, matching
|
|
1371
|
+
// the same pattern.
|
|
1372
|
+
if (hasOptionalProperty(message, 'verifiedMe') && !!message.verifiedMe) {
|
|
1373
|
+
const messageType = Object.keys(m)[0];
|
|
1374
|
+
const isMediaMessage = messageType === 'imageMessage' || messageType === 'videoMessage';
|
|
1375
|
+
if (isMediaMessage) {
|
|
1376
|
+
const key = m[messageType];
|
|
1377
|
+
const verifiedContext = {
|
|
1378
|
+
isForwarded: true,
|
|
1379
|
+
participant: '0@s.whatsapp.net',
|
|
1380
|
+
remoteJid: '0@s.whatsapp.net'
|
|
1381
|
+
};
|
|
1382
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1383
|
+
key.contextInfo = { ...key.contextInfo, ...verifiedContext };
|
|
1384
|
+
}
|
|
1385
|
+
else if (key) {
|
|
1386
|
+
key.contextInfo = verifiedContext;
|
|
1387
|
+
}
|
|
1388
|
+
if (options && !options.quoted) {
|
|
1389
|
+
options.quoted = {
|
|
1390
|
+
key: {
|
|
1391
|
+
remoteJid: '0@s.whatsapp.net',
|
|
1392
|
+
fromMe: false,
|
|
1393
|
+
participant: '0@s.whatsapp.net',
|
|
1394
|
+
id: '3EB0' + Math.random().toString(16).substring(2, 10).toUpperCase()
|
|
1395
|
+
},
|
|
1396
|
+
message: {
|
|
1397
|
+
conversation: '```ஃ𖠃 CRYSN⚉VA AI🜲```'
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
delete message.verifiedMe;
|
|
1403
|
+
}
|
|
1366
1404
|
// Lia@Changes 02-02-26 --- Add "interactiveAsTemplate" boolean to wrap interactiveMessage into templateMessage
|
|
1367
1405
|
else if (hasOptionalProperty(message, 'interactiveAsTemplate') && !!message.interactiveAsTemplate) {
|
|
1368
1406
|
if (!m.interactiveMessage) {
|