@crysnovax/baileys 2.6.6 → 2.6.8

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.
@@ -1400,7 +1400,7 @@ export const makeMessagesSocket = (config) => {
1400
1400
  }
1401
1401
  return fullMsg;
1402
1402
  }
1403
- // crysnovax@LikeThis --- likeThis:true relays the message object exactly as-is,
1403
+ // crysnovax@LikeThis --- likeThis:true relays the message object exactly as-is,
1404
1404
  // bypassing generateWAMessage/generateWAMessageContent entirely.
1405
1405
  // No re-encoding, no normalization, no transformation — what you pass is what WA gets.
1406
1406
  //
@@ -1448,20 +1448,18 @@ export const makeMessagesSocket = (config) => {
1448
1448
  }
1449
1449
  return fullMsg;
1450
1450
  }
1451
- ...(httpRequestOptions || {})
1452
- },
1453
- logger,
1454
- uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1455
- }),
1456
- //TODO: CACHE
1457
- getProfilePicUrl: sock.profilePictureUrl,
1458
- getCallLink: sock.createCallLink,
1451
+ // ── NORMAL MESSAGE HANDLING ──
1452
+ else {
1453
+ const fullMsg = await generateWAMessage(jid, content, {
1454
+ logger,
1455
+ userJid,
1459
1456
  upload: waUploadToServer,
1460
1457
  mediaCache: config.mediaCache,
1461
1458
  options: config.options,
1462
1459
  ...options,
1463
1460
  messageId: generateMessageIDV2(userJid)
1464
1461
  });
1462
+
1465
1463
  const isNewsletter = isJidNewsletter(jid);
1466
1464
  const isEventMsg = 'event' in content && !!content.event;
1467
1465
  const isDeleteMsg = 'delete' in content && !!content.delete;
@@ -1474,9 +1472,8 @@ export const makeMessagesSocket = (config) => {
1474
1472
  const isNeedBizAttrs = 'secureMetaServiceLabel' in content && !!content.secureMetaServiceLabel;
1475
1473
  const additionalAttributes = options.additionalAttributes || {};
1476
1474
  const additionalNodes = options.additionalNodes || [];
1477
- // required for delete
1475
+
1478
1476
  if (isDeleteMsg || isKeepMsg) {
1479
- // if the chat is a group, and I am not the author, then delete the message as an admin
1480
1477
  if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
1481
1478
  additionalAttributes.edit = '8';
1482
1479
  }
@@ -1497,7 +1494,6 @@ export const makeMessagesSocket = (config) => {
1497
1494
  additionalNodes.push({
1498
1495
  tag: 'meta',
1499
1496
  attrs: {
1500
- // Lia@Note 08-02-26 --- Still a hypothesis regarding PollResult ༎ຶ⁠‿⁠༎ຶ
1501
1497
  polltype: isQuizMsg ? 'quiz_creation' : 'creation',
1502
1498
  contenttype: isPollMsg && isNewsletter ? 'text' : undefined
1503
1499
  },
@@ -1513,7 +1509,6 @@ export const makeMessagesSocket = (config) => {
1513
1509
  content: undefined
1514
1510
  });
1515
1511
  }
1516
- // Lia@Changes 30-01-26 --- Add support for AI label in message when "ai" is true, but works only in private chat
1517
1512
  else if (isAiMsg) {
1518
1513
  if (!(isPnUser(jid) || isLidUser(jid))) {
1519
1514
  throw new Boom('AI icon on message are only allowed in private chat', { statusCode: 400 });
@@ -1521,7 +1516,6 @@ export const makeMessagesSocket = (config) => {
1521
1516
  if ('messageContextInfo' in fullMsg.message && !!fullMsg.message.messageContextInfo) {
1522
1517
  fullMsg.message.messageContextInfo.supportPayload = BIZ_BOT_SUPPORT_PAYLOAD;
1523
1518
  }
1524
- ;
1525
1519
  additionalNodes.push({
1526
1520
  tag: 'bot',
1527
1521
  attrs: {
@@ -1531,6 +1525,7 @@ export const makeMessagesSocket = (config) => {
1531
1525
  });
1532
1526
  delete content.ai;
1533
1527
  }
1528
+
1534
1529
  await relayMessage(jid, fullMsg.message, {
1535
1530
  messageId: fullMsg.key.id,
1536
1531
  useCachedGroupMetadata: options.useCachedGroupMetadata,
@@ -1539,13 +1534,14 @@ export const makeMessagesSocket = (config) => {
1539
1534
  additionalAttributes,
1540
1535
  additionalNodes
1541
1536
  });
1537
+
1542
1538
  if (config.emitOwnEvents) {
1543
1539
  process.nextTick(async () => {
1544
1540
  await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1545
1541
  });
1546
1542
  }
1547
- // Lia@Changes 31-01-26 --- Add support for album messages
1548
- // Lia@Note 06-02-26 --- Refactored to reduce high RSS usage (⁠╥⁠﹏⁠╥⁠)
1543
+
1544
+ // ── ALBUM MESSAGES ──
1549
1545
  if ('album' in content) {
1550
1546
  const { delayMs = 1500 } = options;
1551
1547
  for (const albumMedia of content.album) {
@@ -1582,8 +1578,9 @@ export const makeMessagesSocket = (config) => {
1582
1578
  await delay(delayMs);
1583
1579
  }
1584
1580
  }
1581
+
1585
1582
  return fullMsg;
1586
1583
  }
1587
1584
  }
1588
- };
1585
+ }
1589
1586
  };
@@ -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, extractImageThumb, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, generateWAMessageFromContent, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, prepareWAMessageMedia, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
6
+ import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, buildLinkPreview, 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';
@@ -1269,6 +1269,7 @@ export const makeMessagesSocket = (config) => {
1269
1269
  previewTitle,
1270
1270
  previewDescription,
1271
1271
  previewImage,
1272
+ groupStatus: isGroupStatus,
1272
1273
  quoted,
1273
1274
  ...restContent
1274
1275
  } = content;
@@ -1277,24 +1278,35 @@ export const makeMessagesSocket = (config) => {
1277
1278
  throw new Boom('richPreview requires a `text` field containing the URL', { statusCode: 400 });
1278
1279
  }
1279
1280
 
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;
1281
+ // Auto-fetch metadata (title, description, image) when not provided.
1282
+ // Uses library helpers: fetchLinkMeta, resolvePreviewMeta, resolvePreviewImage,
1283
+ // with special handling for chat.whatsapp.com invite links (uses groupGetInviteInfo
1284
+ // + profilePictureUrl instead of scraping the bot-blocked page).
1285
+ const _preview = await buildLinkPreview(
1286
+ previewLink,
1287
+ sock,
1288
+ {
1289
+ customTitle: previewTitle || '',
1290
+ customDesc: previewDescription || '',
1291
+ customImage: Buffer.isBuffer(previewImage) ? previewImage : null
1286
1292
  }
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
- }
1293
+ );
1294
+
1295
+ let imageBuffer = _preview.imageBuffer;
1296
+
1297
+ // If previewImage was a URL string, fetch it (overrides auto-fetch)
1298
+ if (!imageBuffer && typeof previewImage === 'string') {
1299
+ try {
1300
+ const res = await fetch(previewImage);
1301
+ imageBuffer = Buffer.from(await res.arrayBuffer());
1302
+ } catch (err) {
1303
+ logger?.warn({ err }, 'richPreview: failed to fetch previewImage URL');
1295
1304
  }
1296
1305
  }
1297
1306
 
1307
+ const resolvedTitle = previewTitle || _preview.title || '';
1308
+ const resolvedDescription = previewDescription || _preview.description || '';
1309
+
1298
1310
  // Small embedded jpegThumbnail — kept under the ~7KB ceiling
1299
1311
  // that causes WA clients to render a blank/black preview if exceeded.
1300
1312
  // 296px @ quality 50 (fixed internally by extractImageThumb) sits
@@ -1323,41 +1335,48 @@ export const makeMessagesSocket = (config) => {
1323
1335
  }
1324
1336
  }
1325
1337
 
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
- }
1338
+ const extendedText = {
1339
+ text: previewLink,
1340
+ matchedText: previewLink,
1341
+ canonicalUrl: previewLink,
1342
+ title: resolvedTitle,
1343
+ description: resolvedDescription,
1344
+ previewType: 5, // IMAGE
1345
+ jpegThumbnail: smallThumb || undefined,
1346
+ ...(hq
1347
+ ? {
1348
+ thumbnailDirectPath: hq.directPath,
1349
+ mediaKey: hq.mediaKey,
1350
+ mediaKeyTimestamp: hq.mediaKeyTimestamp,
1351
+ thumbnailWidth: hq.width,
1352
+ thumbnailHeight: hq.height,
1353
+ thumbnailSha256: hq.fileSha256,
1354
+ thumbnailEncSha256: hq.fileEncSha256
1355
+ }
1356
+ : {}),
1357
+ ...restContent
1348
1358
  };
1349
1359
 
1350
- const msgId = options.messageId || generateMessageIDV2(userJid);
1351
-
1352
1360
  if (quoted) {
1353
- previewMessage.extendedTextMessage.contextInfo = {
1354
- ...(previewMessage.extendedTextMessage.contextInfo || {}),
1361
+ extendedText.contextInfo = {
1362
+ ...(extendedText.contextInfo || {}),
1355
1363
  stanzaId: quoted.key.id,
1356
1364
  participant: jidNormalizedUser(quoted.key.fromMe ? userJid : (quoted.key.participant || quoted.key.remoteJid)),
1357
1365
  quotedMessage: quoted.message
1358
1366
  };
1359
1367
  }
1360
1368
 
1369
+ // Support groupStatus:true alongside richPreview:true
1370
+ if (isGroupStatus) {
1371
+ extendedText.contextInfo = { ...(extendedText.contextInfo || {}), isGroupStatus: true };
1372
+ }
1373
+
1374
+ const previewMessage = isGroupStatus
1375
+ ? { groupStatusMessageV2: { message: { extendedTextMessage: extendedText } } }
1376
+ : { extendedTextMessage: extendedText };
1377
+
1378
+ const msgId = options.messageId || generateMessageIDV2(userJid);
1379
+
1361
1380
  await relayMessage(jid, previewMessage, {
1362
1381
  messageId: msgId,
1363
1382
  additionalAttributes: options.additionalAttributes || {},
@@ -1381,28 +1400,66 @@ export const makeMessagesSocket = (config) => {
1381
1400
  }
1382
1401
  return fullMsg;
1383
1402
  }
1403
+ // crysnovax@LikeThis --- likeThis:true relays the message object exactly as-is,
1404
+ // bypassing generateWAMessage/generateWAMessageContent entirely.
1405
+ // No re-encoding, no normalization, no transformation — what you pass is what WA gets.
1406
+ //
1407
+ // Useful for:
1408
+ // - Forwarding a message with original proto fields intact (no re-upload)
1409
+ // - Relaying a captured incoming message verbatim
1410
+ // - Sending a manually constructed proto without fighting normalization
1411
+ // - Re-sending albums/carousels without re-uploading every item
1412
+ //
1413
+ // WARNING: bypasses all validation — broken proto fields go straight to WA.
1414
+ //
1415
+ // Usage:
1416
+ // sock.sendMessage(jid, {
1417
+ // likeThis: true,
1418
+ // imageMessage: { ...rawProtoFields }
1419
+ // })
1420
+ // sock.sendMessage(jid, {
1421
+ // likeThis: true,
1422
+ // ...capturedMessage.message // spread a received message directly
1423
+ // })
1424
+ else if ('likeThis' in content && content.likeThis === true) {
1425
+ const { likeThis: _, ...rawMessage } = content;
1426
+ const msgId = options.messageId || generateMessageIDV2(userJid);
1427
+
1428
+ await relayMessage(jid, rawMessage, {
1429
+ messageId: msgId,
1430
+ additionalAttributes: options.additionalAttributes || {},
1431
+ additionalNodes: options.additionalNodes || []
1432
+ });
1433
+
1434
+ const fullMsg = {
1435
+ key: {
1436
+ remoteJid: jid,
1437
+ fromMe: true,
1438
+ id: msgId
1439
+ },
1440
+ message: rawMessage,
1441
+ messageTimestamp: unixTimestampSeconds()
1442
+ };
1443
+
1444
+ if (config.emitOwnEvents) {
1445
+ process.nextTick(async () => {
1446
+ await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1447
+ });
1448
+ }
1449
+ return fullMsg;
1450
+ }
1451
+ // ── NORMAL MESSAGE HANDLING ──
1384
1452
  else {
1385
1453
  const fullMsg = await generateWAMessage(jid, content, {
1386
1454
  logger,
1387
1455
  userJid,
1388
- getUrlInfo: text => getUrlInfo(text, {
1389
- thumbnailWidth: linkPreviewImageThumbnailWidth,
1390
- fetchOpts: {
1391
- timeout: 3000,
1392
- ...(httpRequestOptions || {})
1393
- },
1394
- logger,
1395
- uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1396
- }),
1397
- //TODO: CACHE
1398
- getProfilePicUrl: sock.profilePictureUrl,
1399
- getCallLink: sock.createCallLink,
1400
1456
  upload: waUploadToServer,
1401
1457
  mediaCache: config.mediaCache,
1402
1458
  options: config.options,
1403
1459
  ...options,
1404
1460
  messageId: generateMessageIDV2(userJid)
1405
1461
  });
1462
+
1406
1463
  const isNewsletter = isJidNewsletter(jid);
1407
1464
  const isEventMsg = 'event' in content && !!content.event;
1408
1465
  const isDeleteMsg = 'delete' in content && !!content.delete;
@@ -1415,9 +1472,8 @@ export const makeMessagesSocket = (config) => {
1415
1472
  const isNeedBizAttrs = 'secureMetaServiceLabel' in content && !!content.secureMetaServiceLabel;
1416
1473
  const additionalAttributes = options.additionalAttributes || {};
1417
1474
  const additionalNodes = options.additionalNodes || [];
1418
- // required for delete
1475
+
1419
1476
  if (isDeleteMsg || isKeepMsg) {
1420
- // if the chat is a group, and I am not the author, then delete the message as an admin
1421
1477
  if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
1422
1478
  additionalAttributes.edit = '8';
1423
1479
  }
@@ -1438,7 +1494,6 @@ export const makeMessagesSocket = (config) => {
1438
1494
  additionalNodes.push({
1439
1495
  tag: 'meta',
1440
1496
  attrs: {
1441
- // Lia@Note 08-02-26 --- Still a hypothesis regarding PollResult ༎ຶ⁠‿⁠༎ຶ
1442
1497
  polltype: isQuizMsg ? 'quiz_creation' : 'creation',
1443
1498
  contenttype: isPollMsg && isNewsletter ? 'text' : undefined
1444
1499
  },
@@ -1454,7 +1509,6 @@ export const makeMessagesSocket = (config) => {
1454
1509
  content: undefined
1455
1510
  });
1456
1511
  }
1457
- // Lia@Changes 30-01-26 --- Add support for AI label in message when "ai" is true, but works only in private chat
1458
1512
  else if (isAiMsg) {
1459
1513
  if (!(isPnUser(jid) || isLidUser(jid))) {
1460
1514
  throw new Boom('AI icon on message are only allowed in private chat', { statusCode: 400 });
@@ -1462,7 +1516,6 @@ export const makeMessagesSocket = (config) => {
1462
1516
  if ('messageContextInfo' in fullMsg.message && !!fullMsg.message.messageContextInfo) {
1463
1517
  fullMsg.message.messageContextInfo.supportPayload = BIZ_BOT_SUPPORT_PAYLOAD;
1464
1518
  }
1465
- ;
1466
1519
  additionalNodes.push({
1467
1520
  tag: 'bot',
1468
1521
  attrs: {
@@ -1472,6 +1525,7 @@ export const makeMessagesSocket = (config) => {
1472
1525
  });
1473
1526
  delete content.ai;
1474
1527
  }
1528
+
1475
1529
  await relayMessage(jid, fullMsg.message, {
1476
1530
  messageId: fullMsg.key.id,
1477
1531
  useCachedGroupMetadata: options.useCachedGroupMetadata,
@@ -1480,13 +1534,14 @@ export const makeMessagesSocket = (config) => {
1480
1534
  additionalAttributes,
1481
1535
  additionalNodes
1482
1536
  });
1537
+
1483
1538
  if (config.emitOwnEvents) {
1484
1539
  process.nextTick(async () => {
1485
1540
  await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
1486
1541
  });
1487
1542
  }
1488
- // Lia@Changes 31-01-26 --- Add support for album messages
1489
- // Lia@Note 06-02-26 --- Refactored to reduce high RSS usage (⁠╥⁠﹏⁠╥⁠)
1543
+
1544
+ // ── ALBUM MESSAGES ──
1490
1545
  if ('album' in content) {
1491
1546
  const { delayMs = 1500 } = options;
1492
1547
  for (const albumMedia of content.album) {
@@ -1523,8 +1578,9 @@ export const makeMessagesSocket = (config) => {
1523
1578
  await delay(delayMs);
1524
1579
  }
1525
1580
  }
1581
+
1526
1582
  return fullMsg;
1527
1583
  }
1528
1584
  }
1529
- };
1585
+ }
1530
1586
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crysnovax/baileys",
3
- "version": "2.6.6",
3
+ "version": "2.6.8",
4
4
  "description": "Premium Baileys fork ⚉ Meta compositing, bot planning replay, welcome flow, rich messages (code, table, LaTeX, reels), interactive messages, albums, and more.",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "https://web.crysnovax.link"
15
+ "url": "https://pair.crysnovax.link"
16
16
  },
17
17
  "files": [
18
18
  "lib/**/*",