@yemo-dev/yebail 1.1.2 → 1.1.3

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/EXAMPLES.md CHANGED
@@ -1,9 +1,13 @@
1
- # yebails code examples (`sendMessage`)
1
+ # yebail code examples (`sendMessage`)
2
+
3
+ > [!NOTE]
4
+ > **Mengapa yebail bknnya yebails?**
5
+ > Karena `yebail` adalah suksesor dari `yebails` yang mendukung fitur pesan interaktif lebih lengkap (seperti full button, native flow, dll) dan optimalisasi untuk WhatsApp versi terbaru.
2
6
 
3
7
  GitHub-only distribution. After `npm install` or `npm install github:yemo-dev/baileys`:
4
8
 
5
9
  ```js
6
- const makeWASocket = require('yebails').default
10
+ const makeWASocket = require('@yemo-dev/yebail').default
7
11
  ```
8
12
 
9
13
  From a local clone (without global install):
@@ -23,7 +27,7 @@ yebails supports **local** and **cloud** databases the same way: you choose how
23
27
  ### 1) Filesystem (default)
24
28
 
25
29
  ```js
26
- const { default: makeWASocket, useMultiFileAuthState } = require('yebails')
30
+ const { default: makeWASocket, useMultiFileAuthState } = require('@yemo-dev/yebail')
27
31
 
28
32
  const { state, saveCreds } = await useMultiFileAuthState('./auth_info_baileys')
29
33
  const sock = makeWASocket({ auth: state })
@@ -35,7 +39,7 @@ sock.ev.on('creds.update', saveCreds)
35
39
  Install the optional native driver: `npm install better-sqlite3`
36
40
 
37
41
  ```js
38
- const { default: makeWASocket, useSqliteAuthState } = require('yebails')
42
+ const { default: makeWASocket, useSqliteAuthState } = require('@yemo-dev/yebail')
39
43
 
40
44
  const { state, saveCreds } = await useSqliteAuthState('./wa-session.db')
41
45
  const sock = makeWASocket({ auth: state })
@@ -50,7 +54,7 @@ Implement three async functions: **`get(key)`** → JSON string or `null`, **`se
50
54
 
51
55
  ```js
52
56
  const Redis = require('ioredis')
53
- const { default: makeWASocket, useCustomAuthState } = require('yebails')
57
+ const { default: makeWASocket, useCustomAuthState } = require('@yemo-dev/yebail')
54
58
 
55
59
  const redis = new Redis(process.env.REDIS_URL)
56
60
  const prefix = 'yebails:session:'
@@ -626,16 +630,88 @@ await sock.sendMessage(jid, {
626
630
  })
627
631
  ```
628
632
 
629
- ## AI marker (send option)
633
+ ---
634
+
635
+ ## Interactive Messages (Buttons & Native Flow)
636
+
637
+ `yebails` supports the latest WhatsApp interactive message formats:
638
+
639
+ ### 1) Buttons Message
640
+ ```js
641
+ await sock.sendMessage(jid, {
642
+ text: "Pilih Menu",
643
+ footer: "yebail-pro",
644
+ buttons: [
645
+ { buttonId: 'id1', buttonText: { displayText: 'Button 1' }, type: 1 },
646
+ { buttonId: 'id2', buttonText: { displayText: 'Button 2' }, type: 1 }
647
+ ],
648
+ headerType: 1
649
+ })
650
+ ```
651
+
652
+ ### 2) List Message
653
+ ```js
654
+ await sock.sendMessage(jid, {
655
+ text: "Daftar Layanan",
656
+ footer: "yebail-pro",
657
+ title: "Silakan Pilih",
658
+ buttonText: "Klik di sini",
659
+ sections: [
660
+ {
661
+ title: "Kategori 1",
662
+ rows: [
663
+ { title: "Opsi 1", rowId: "opt1", description: "Deskripsi 1" },
664
+ { title: "Opsi 2", rowId: "opt2", description: "Deskripsi 2" }
665
+ ]
666
+ }
667
+ ]
668
+ })
669
+ ```
630
670
 
671
+ ### 3) Native Flow Message (Full Buttons)
631
672
  ```js
632
- await sock.sendMessage(jid, { text: 'Hello' }, { ai: true })
673
+ await sock.sendMessage(jid, {
674
+ viewOnceMessage: {
675
+ message: {
676
+ interactiveMessage: {
677
+ header: { title: "Header Title" },
678
+ body: { text: "Body Text" },
679
+ footer: { text: "Footer Text" },
680
+ nativeFlowMessage: {
681
+ buttons: [
682
+ {
683
+ name: "cta_url",
684
+ buttonParamsJson: JSON.stringify({
685
+ display_text: "Buka Google",
686
+ url: "https://google.com",
687
+ merchant_url: "https://google.com"
688
+ })
689
+ },
690
+ {
691
+ name: "quick_reply",
692
+ buttonParamsJson: JSON.stringify({
693
+ display_text: "Balas Cepat",
694
+ id: "reply_id"
695
+ })
696
+ }
697
+ ]
698
+ }
699
+ }
700
+ }
701
+ }
702
+ })
633
703
  ```
634
704
 
705
+ ### 4) Status Mentions
706
+ ```js
707
+ await sock.sendStatusMentions({
708
+ image: { url: './status.jpg' },
709
+ caption: 'Hello Status!'
710
+ }, ['6281234567890@s.whatsapp.net', '6289876543210@s.whatsapp.net'])
711
+
635
712
  ---
636
713
 
637
714
  ## Notes
638
715
 
639
716
  - Native button names (`name` in `interactiveButtons`) must match what the server expects; the examples above follow common Baileys patterns.
640
717
  - Some message types are only stable in private chats or only available for business accounts.
641
- - For `relayMessage` with an AI flag, use uppercase `AI: true` according to your socket implementation.
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # @yemo-dev/yebail
2
2
 
3
- **@yemo-dev/yebail** is a high-performance, WebSocket-based WhatsApp Web API library. It is a specialized distribution of Baileys, optimized for stability and automated version tracking.
3
+ **@yemo-dev/yebail** is a high-performance, WebSocket-based WhatsApp Web API library. It is a specialized, feature-rich distribution of Baileys, optimized for interactive messages and automated version tracking.
4
+
5
+ > [!NOTE]
6
+ > **Mengapa yebail bknnya yebails?**
7
+ > Karena `yebail` adalah suksesor dari `yebails` yang mendukung fitur pesan interaktif lebih lengkap (seperti full button, native flow, dll) dan optimalisasi untuk WhatsApp versi terbaru.
4
8
 
5
9
  > [!TIP]
6
10
  > This version is maintained with an **Auto-Update** system that tracks the latest WhatsApp Web revisions to ensure continuous compatibility.
@@ -29,7 +33,7 @@ npm install github:yemo-dev/baileys
29
33
 
30
34
  ## Import
31
35
 
32
- After installing from npm, the module name is `@yemo-dev/yebail`:
36
+ After installing from npm, the module name is `@yemo-dev/yebails`:
33
37
 
34
38
  ```js
35
39
  const {
@@ -268,21 +268,51 @@ const makeMessagesSocket = (config) => {
268
268
  }));
269
269
  return { nodes, shouldIncludeDeviceIdentity };
270
270
  };
271
- const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
272
- var _a;
271
+ const profilePictureUrl = async (jid) => {
272
+ if ((0, WABinary_1.isJidNewsletter)(jid)) {
273
+ const metadata = await sock.newsletterMetadata('JID', jid);
274
+ return (0, Utils_1.getUrlFromDirectPath)(metadata.thread_metadata.picture?.direct_path || '');
275
+ }
276
+ else {
277
+ const result = await query({
278
+ tag: 'iq',
279
+ attrs: {
280
+ target: (0, WABinary_1.jidNormalizedUser)(jid),
281
+ to: WABinary_1.S_WHATSAPP_NET,
282
+ type: 'get',
283
+ xmlns: 'w:profile:picture'
284
+ },
285
+ content: [{
286
+ tag: 'picture',
287
+ attrs: {
288
+ type: 'image',
289
+ query: 'url'
290
+ }
291
+ }]
292
+ });
293
+ const child = (0, WABinary_1.getBinaryNodeChild)(result, 'picture');
294
+ return child?.attrs?.url || null;
295
+ }
296
+ };
297
+ const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes }) => {
273
298
  const meId = authState.creds.me.id;
274
- let shouldIncludeDeviceIdentity = false;
275
- const { user, server } = (0, WABinary_1.jidDecode)(jid);
299
+ const meLid = authState.creds.me?.lid;
300
+ const isRetryResend = Boolean(participant?.jid);
301
+ let shouldIncludeDeviceIdentity = isRetryResend;
302
+ let didPushAdditional = false;
276
303
  const statusJid = 'status@broadcast';
304
+ const { user, server } = (0, WABinary_1.jidDecode)(jid);
277
305
  const isGroup = server === 'g.us';
278
- const isNewsletter = server === 'newsletter';
279
306
  const isStatus = jid === statusJid;
280
307
  const isLid = server === 'lid';
281
- msgId = msgId || (0, Utils_1.generateMessageIDV2)((_a = sock.user) === null || _a === void 0 ? void 0 : _a.id);
308
+ const isNewsletter = server === 'newsletter';
309
+ const isGroupOrStatus = isGroup || isStatus;
310
+ const finalJid = jid;
311
+ msgId = msgId || (0, Utils_1.generateMessageID)(meId);
282
312
  useUserDevicesCache = useUserDevicesCache !== false;
283
313
  useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
284
314
  const participants = [];
285
- const destinationJid = (!isStatus) ? (0, WABinary_1.jidEncode)(user, isLid ? 'lid' : isGroup ? 'g.us' : isNewsletter ? 'newsletter' : 's.whatsapp.net') : statusJid;
315
+ const destinationJid = !isStatus ? finalJid : statusJid;
286
316
  const binaryNodeContent = [];
287
317
  const devices = [];
288
318
  const meMsg = {
@@ -293,34 +323,63 @@ const makeMessagesSocket = (config) => {
293
323
  messageContextInfo: message.messageContextInfo
294
324
  };
295
325
  const extraAttrs = {};
326
+ const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/;
327
+ const messages = (0, Utils_1.normalizeMessageContent)(message);
328
+ const buttonType = getButtonType(messages);
329
+ const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3;
296
330
  if (participant) {
297
- // when the retry request is not for a group
298
- // only send to the specific device that asked for a retry
299
- // otherwise the message is sent out to every device that should be a recipient
300
331
  if (!isGroup && !isStatus) {
301
- additionalAttributes = { ...additionalAttributes, 'device_fanout': 'false' };
332
+ additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
302
333
  }
303
334
  const { user, device } = (0, WABinary_1.jidDecode)(participant.jid);
304
- devices.push({ user, device });
335
+ devices.push({
336
+ user,
337
+ device,
338
+ jid: participant.jid
339
+ });
305
340
  }
306
341
  await authState.keys.transaction(async () => {
307
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
308
342
  const mediaType = getMediaType(message);
309
343
  if (mediaType) {
310
344
  extraAttrs['mediatype'] = mediaType;
311
345
  }
312
- if ((_a = (0, Utils_1.normalizeMessageContent)(message)) === null || _a === void 0 ? void 0 : _a.pinInChatMessage) {
346
+ if (isNewsletter) {
347
+ const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
348
+ const bytes = (0, Utils_1.encodeNewsletterMessage)(patched);
349
+ binaryNodeContent.push({
350
+ tag: 'plaintext',
351
+ attrs: {},
352
+ content: bytes
353
+ });
354
+ const stanza = {
355
+ tag: 'message',
356
+ attrs: {
357
+ to: jid,
358
+ id: msgId,
359
+ type: getTypeMessage(message),
360
+ ...(additionalAttributes || {})
361
+ },
362
+ content: binaryNodeContent
363
+ };
364
+ logger.debug({ msgId }, `sending newsletter message to ${jid}`);
365
+ await sendNode(stanza);
366
+ return;
367
+ }
368
+ if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
313
369
  extraAttrs['decrypt-fail'] = 'hide';
314
370
  }
315
- if (isGroup || isStatus) {
371
+ if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
372
+ extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options';
373
+ }
374
+ if (isGroupOrStatus && !isRetryResend) {
316
375
  const [groupData, senderKeyMap] = await Promise.all([
317
376
  (async () => {
318
377
  let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined;
319
- if (groupData && Array.isArray(groupData === null || groupData === void 0 ? void 0 : groupData.participants)) {
378
+ if (groupData && Array.isArray(groupData?.participants)) {
320
379
  logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata');
321
380
  }
322
381
  else if (!isStatus) {
323
- groupData = await groupMetadata(jid);
382
+ groupData = await sock.groupMetadata(jid);
324
383
  }
325
384
  return groupData;
326
385
  })(),
@@ -332,125 +391,169 @@ const makeMessagesSocket = (config) => {
332
391
  return {};
333
392
  })()
334
393
  ]);
335
- if (!participant) {
336
- const participantsList = (groupData && !isStatus) ? groupData.participants.map(p => p.id) : [];
337
- if (isStatus && statusJidList) {
338
- participantsList.push(...statusJidList);
339
- }
340
- if (!isStatus) {
341
- additionalAttributes = {
342
- ...additionalAttributes,
343
- // eslint-disable-next-line camelcase
344
- addressing_mode: (groupData === null || groupData === void 0 ? void 0 : groupData.addressingMode) || 'pn'
345
- };
346
- }
347
- const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false, ((_k = message.protocolMessage) === null || _k === void 0 ? void 0 : _k.type) === WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE);
348
- devices.push(...additionalDevices);
394
+ const participantsList = groupData ? groupData.participants.map(p => p.id) : [];
395
+ if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
396
+ additionalAttributes = {
397
+ ...additionalAttributes,
398
+ expiration: groupData.ephemeralDuration.toString()
399
+ };
400
+ }
401
+ if (isStatus && statusJidList) {
402
+ participantsList.push(...statusJidList);
403
+ }
404
+ const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
405
+ devices.push(...additionalDevices);
406
+ if (isGroup) {
407
+ additionalAttributes = {
408
+ ...additionalAttributes,
409
+ addressing_mode: groupData?.addressingMode || 'lid'
410
+ };
349
411
  }
350
412
  const patched = await patchMessageBeforeSending(message);
351
413
  if (Array.isArray(patched)) {
352
414
  throw new boom_1.Boom('Per-jid patching is not supported in groups');
353
415
  }
354
416
  const bytes = (0, Utils_1.encodeWAMessage)(patched);
417
+ const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
418
+ const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
355
419
  const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
356
420
  group: destinationJid,
357
421
  data: bytes,
358
- meId,
422
+ meId: groupSenderIdentity
359
423
  });
360
- const senderKeyJids = [];
361
- // ensure a connection is established with every device
362
- for (const { user, device } of devices) {
363
- const jid = (0, WABinary_1.jidEncode)(user, (groupData === null || groupData === void 0 ? void 0 : groupData.addressingMode) === 'lid' ? 'lid' : 's.whatsapp.net', device);
364
- if (!senderKeyMap[jid] || !!participant) {
365
- senderKeyJids.push(jid);
366
- // store that this person has had the sender keys sent to them
367
- senderKeyMap[jid] = true;
424
+ const senderKeyRecipients = [];
425
+ for (const device of devices) {
426
+ const deviceJid = device.jid;
427
+ const hasKey = !!senderKeyMap[deviceJid];
428
+ if ((!hasKey || !!participant) &&
429
+ !(0, WABinary_1.isHostedLidUser)(deviceJid) &&
430
+ !(0, WABinary_1.isHostedPnUser)(deviceJid) &&
431
+ device.device !== 99) {
432
+ senderKeyRecipients.push(deviceJid);
433
+ senderKeyMap[deviceJid] = true;
368
434
  }
369
435
  }
370
- // if there are some participants with whom the session has not been established
371
- // if there are, we re-send the senderkey
372
- if (senderKeyJids.length) {
373
- logger.debug({ senderKeyJids }, 'sending new sender key');
436
+ if (senderKeyRecipients.length) {
437
+ logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
374
438
  const senderKeyMsg = {
375
439
  senderKeyDistributionMessage: {
376
440
  axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
377
441
  groupId: destinationJid
378
442
  }
379
443
  };
380
- await assertSessions(senderKeyJids, false);
381
- const result = await createParticipantNodes(senderKeyJids, senderKeyMsg, extraAttrs);
444
+ const senderKeySessionTargets = senderKeyRecipients;
445
+ await assertSessions(senderKeySessionTargets);
446
+ const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
382
447
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
383
448
  participants.push(...result.nodes);
384
449
  }
385
450
  binaryNodeContent.push({
386
451
  tag: 'enc',
387
- attrs: { v: '2', type: 'skmsg' },
452
+ attrs: { v: '2', type: 'skmsg', ...extraAttrs },
388
453
  content: ciphertext
389
454
  });
390
455
  await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
391
456
  }
392
- else if (isNewsletter) {
393
- // Message edit
394
- if ((_b = message.protocolMessage) === null || _b === void 0 ? void 0 : _b.editedMessage) {
395
- msgId = (_c = message.protocolMessage.key) === null || _c === void 0 ? void 0 : _c.id;
396
- message = message.protocolMessage.editedMessage;
457
+ else if (!isGroupOrStatus && !isRetryResend) {
458
+ /** ADDRESSING CONSISTENCY: Match own identity to conversation context **/
459
+ let ownId = meId;
460
+ if (isLid && meLid) {
461
+ ownId = meLid;
462
+ logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
397
463
  }
398
- // Message delete
399
- if (((_d = message.protocolMessage) === null || _d === void 0 ? void 0 : _d.type) === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
400
- msgId = (_e = message.protocolMessage.key) === null || _e === void 0 ? void 0 : _e.id;
401
- message = {};
402
- }
403
- const patched = await patchMessageBeforeSending(message, []);
404
- if (Array.isArray(patched)) {
405
- throw new boom_1.Boom('Per-jid patching is not supported in channel');
464
+ else {
465
+ logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
406
466
  }
407
- const bytes = (0, Utils_1.encodeNewsletterMessage)(patched);
408
- binaryNodeContent.push({
409
- tag: 'plaintext',
410
- attrs: mediaType ? { mediatype: mediaType } : {},
411
- content: bytes
467
+ const { user: ownUser } = (0, WABinary_1.jidDecode)(ownId);
468
+ const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
469
+ devices.push({
470
+ user,
471
+ device: 0,
472
+ jid: (0, WABinary_1.jidEncode)(user, targetUserServer, 0)
412
473
  });
413
- }
414
- else {
415
- const { user: meUser } = (0, WABinary_1.jidDecode)(meId);
416
- if (!participant) {
417
- devices.push({ user });
418
- if (user !== meUser) {
419
- devices.push({ user: meUser });
420
- }
421
- if ((additionalAttributes === null || additionalAttributes === void 0 ? void 0 : additionalAttributes['category']) !== 'peer') {
422
- const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true, ((_k = message.protocolMessage) === null || _k === void 0 ? void 0 : _k.type) === WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE);
423
- devices.push(...additionalDevices);
424
- }
474
+ if (user !== ownUser) {
475
+ const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
476
+ const ownUserForAddressing = isLid && meLid ? (0, WABinary_1.jidDecode)(meLid).user : (0, WABinary_1.jidDecode)(meId).user;
477
+ devices.push({
478
+ user: ownUserForAddressing,
479
+ device: 0,
480
+ jid: (0, WABinary_1.jidEncode)(ownUserForAddressing, ownUserServer, 0)
481
+ });
425
482
  }
426
- const allJids = [];
427
- const meJids = [];
428
- const otherJids = [];
429
- for (const { user, device } of devices) {
430
- const isMe = user === meUser;
431
- const jid = (0, WABinary_1.jidEncode)(isMe && isLid ? ((_g = (_f = authState.creds) === null || _f === void 0 ? void 0 : _f.me) === null || _g === void 0 ? void 0 : _g.lid.split(':')[0]) || user : user, isLid ? 'lid' : 's.whatsapp.net', device);
483
+ if (additionalAttributes?.['category'] !== 'peer') {
484
+ devices.length = 0;
485
+ const senderIdentity = isLid && meLid
486
+ ? (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(meLid)?.user, 'lid', undefined)
487
+ : (0, WABinary_1.jidEncode)((0, WABinary_1.jidDecode)(meId)?.user, 's.whatsapp.net', undefined);
488
+ const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
489
+ devices.push(...sessionDevices);
490
+ logger.debug({
491
+ deviceCount: devices.length,
492
+ devices: devices.map(d => `${d.user}:${d.device}@${(0, WABinary_1.jidDecode)(d.jid)?.server}`)
493
+ }, 'Device enumeration complete with unified addressing');
494
+ }
495
+ const allRecipients = [];
496
+ const meRecipients = [];
497
+ const otherRecipients = [];
498
+ const { user: mePnUser } = (0, WABinary_1.jidDecode)(meId);
499
+ const { user: meLidUser } = meLid ? (0, WABinary_1.jidDecode)(meLid) : { user: null };
500
+ for (const { user, jid } of devices) {
501
+ const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
502
+ if (isExactSenderDevice) {
503
+ logger.debug({ jid, meId, meLid }, 'Skipping exact sender device');
504
+ continue;
505
+ }
506
+ const isMe = user === mePnUser || user === meLidUser;
432
507
  if (isMe) {
433
- meJids.push(jid);
508
+ meRecipients.push(jid);
434
509
  }
435
510
  else {
436
- otherJids.push(jid);
511
+ otherRecipients.push(jid);
437
512
  }
438
- allJids.push(jid);
513
+ allRecipients.push(jid);
439
514
  }
440
- await assertSessions(allJids, false);
515
+ await assertSessions(allRecipients);
441
516
  const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
442
- createParticipantNodes(meJids, meMsg, extraAttrs),
443
- createParticipantNodes(otherJids, message, extraAttrs)
517
+ createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
518
+ createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
444
519
  ]);
445
520
  participants.push(...meNodes);
446
521
  participants.push(...otherNodes);
522
+ if (meRecipients.length > 0 || otherRecipients.length > 0) {
523
+ extraAttrs['phash'] = (0, Utils_1.generateParticipantHashV2)([...meRecipients, ...otherRecipients]);
524
+ }
447
525
  shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
448
526
  }
527
+ if (isRetryResend) {
528
+ const isParticipantLid = (0, WABinary_1.isLidUser)(participant.jid);
529
+ const isMe = (0, WABinary_1.areJidsSameUser)(participant.jid, isParticipantLid ? meLid : meId);
530
+ const encodedMessageToSend = isMe
531
+ ? (0, Utils_1.encodeWAMessage)({
532
+ deviceSentMessage: {
533
+ destinationJid,
534
+ message
535
+ }
536
+ })
537
+ : (0, Utils_1.encodeWAMessage)(message);
538
+ const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
539
+ data: encodedMessageToSend,
540
+ jid: participant.jid
541
+ });
542
+ binaryNodeContent.push({
543
+ tag: 'enc',
544
+ attrs: {
545
+ v: '2',
546
+ type,
547
+ count: participant.count.toString()
548
+ },
549
+ content: encryptedContent
550
+ });
551
+ }
449
552
  if (participants.length) {
450
- if ((additionalAttributes === null || additionalAttributes === void 0 ? void 0 : additionalAttributes['category']) === 'peer') {
451
- const peerNode = (_j = (_h = participants[0]) === null || _h === void 0 ? void 0 : _h.content) === null || _j === void 0 ? void 0 : _j[0];
553
+ if (additionalAttributes?.['category'] === 'peer') {
554
+ const peerNode = participants[0]?.content?.[0];
452
555
  if (peerNode) {
453
- binaryNodeContent.push(peerNode); // push only enc
556
+ binaryNodeContent.push(peerNode);
454
557
  }
455
558
  }
456
559
  else {
@@ -465,14 +568,12 @@ const makeMessagesSocket = (config) => {
465
568
  tag: 'message',
466
569
  attrs: {
467
570
  id: msgId,
468
- type: isNewsletter ? getTypeMessage(message) : 'text',
571
+ to: destinationJid,
572
+ type: getTypeMessage(message),
469
573
  ...(additionalAttributes || {})
470
574
  },
471
575
  content: binaryNodeContent
472
576
  };
473
- // if the participant to send to is explicitly specified (generally retry recp)
474
- // ensure the message is only sent to that person
475
- // if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
476
577
  if (participant) {
477
578
  if ((0, WABinary_1.isJidGroup)(destinationJid)) {
478
579
  stanza.attrs.to = destinationJid;
@@ -497,14 +598,47 @@ const makeMessagesSocket = (config) => {
497
598
  });
498
599
  logger.debug({ jid }, 'adding device identity');
499
600
  }
500
- if (additionalNodes && additionalNodes.length > 0) {
501
- stanza.content.push(...additionalNodes);
601
+ const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {};
602
+ const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
603
+ if (tcTokenBuffer) {
604
+ stanza.content.push({
605
+ tag: 'tctoken',
606
+ attrs: {},
607
+ content: tcTokenBuffer
608
+ });
502
609
  }
503
- const messages = (0, Utils_1.normalizeMessageContent)(message);
504
- const buttonType = getButtonType(messages);
505
- if (((0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidUser)(jid)) && buttonType) {
506
- const bizNode = getButtonArgs(messages);
507
- stanza.content.push(bizNode);
610
+ if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
611
+ stanza.content.push({
612
+ tag: 'multicast',
613
+ attrs: {}
614
+ });
615
+ }
616
+ if (pollMessage || messages.eventMessage) {
617
+ stanza.content.push({
618
+ tag: 'meta',
619
+ attrs: messages.eventMessage ? {
620
+ event_type: 'creation'
621
+ } : isNewsletter ? {
622
+ polltype: 'creation',
623
+ contenttype: pollMessage?.pollContentType === 2 ? 'image' : 'text'
624
+ } : {
625
+ polltype: 'creation'
626
+ }
627
+ });
628
+ }
629
+ if (!isNewsletter && buttonType) {
630
+ const buttonsNode = getButtonArgs(messages);
631
+ const filteredButtons = (0, WABinary_1.getBinaryFilteredButtons)(additionalNodes ? additionalNodes : []);
632
+ if (filteredButtons) {
633
+ stanza.content.push(...additionalNodes);
634
+ didPushAdditional = true;
635
+ }
636
+ else {
637
+ stanza.content.push(buttonsNode);
638
+ }
639
+ }
640
+ if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
641
+ stanza.content.push(...additionalNodes);
508
642
  }
509
643
  logger.debug({ msgId }, `sending message to ${participants.length} devices`);
510
644
  await sendNode(stanza);
@@ -512,28 +646,17 @@ const makeMessagesSocket = (config) => {
512
646
  return msgId;
513
647
  };
514
648
  const getTypeMessage = (msg) => {
515
- if (msg.viewOnceMessage) {
516
- return getTypeMessage(msg.viewOnceMessage.message);
517
- }
518
- else if (msg.viewOnceMessageV2) {
519
- return getTypeMessage(msg.viewOnceMessageV2.message);
520
- }
521
- else if (msg.viewOnceMessageV2Extension) {
522
- return getTypeMessage(msg.viewOnceMessageV2Extension.message);
523
- }
524
- else if (msg.ephemeralMessage) {
525
- return getTypeMessage(msg.ephemeralMessage.message);
526
- }
527
- else if (msg.documentWithCaptionMessage) {
528
- return getTypeMessage(msg.documentWithCaptionMessage.message);
649
+ const message = (0, Utils_1.normalizeMessageContent)(msg);
650
+ if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
651
+ return 'poll';
529
652
  }
530
- else if (msg.reactionMessage) {
653
+ else if (message.reactionMessage) {
531
654
  return 'reaction';
532
655
  }
533
- else if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3 || msg.pollUpdateMessage) {
534
- return 'poll';
656
+ else if (message.eventMessage) {
657
+ return 'event';
535
658
  }
536
- else if (getMediaType(msg)) {
659
+ else if (getMediaType(message)) {
537
660
  return 'media';
538
661
  }
539
662
  else {
@@ -544,27 +667,39 @@ const makeMessagesSocket = (config) => {
544
667
  if (message.imageMessage) {
545
668
  return 'image';
546
669
  }
670
+ else if (message.stickerMessage) {
671
+ return message.stickerMessage.isLottie ? '1p_sticker' : message.stickerMessage.isAvatar ? 'avatar_sticker' : 'sticker';
672
+ }
547
673
  else if (message.videoMessage) {
548
674
  return message.videoMessage.gifPlayback ? 'gif' : 'video';
549
675
  }
550
676
  else if (message.audioMessage) {
551
677
  return message.audioMessage.ptt ? 'ptt' : 'audio';
552
678
  }
679
+ else if (message.ptvMessage) {
680
+ return 'ptv';
681
+ }
682
+ else if (message.albumMessage) {
683
+ return 'collection';
684
+ }
553
685
  else if (message.contactMessage) {
554
686
  return 'vcard';
555
687
  }
556
688
  else if (message.documentMessage) {
557
689
  return 'document';
558
690
  }
691
+ else if (message.stickerPackMessage) {
692
+ return 'sticker_pack';
693
+ }
559
694
  else if (message.contactsArrayMessage) {
560
695
  return 'contact_array';
561
696
  }
697
+ else if (message.locationMessage) {
698
+ return 'location';
699
+ }
562
700
  else if (message.liveLocationMessage) {
563
701
  return 'livelocation';
564
702
  }
565
- else if (message.stickerMessage) {
566
- return 'sticker';
567
- }
568
703
  else if (message.listMessage) {
569
704
  return 'list';
570
705
  }
@@ -583,7 +718,13 @@ const makeMessagesSocket = (config) => {
583
718
  else if (message.interactiveResponseMessage) {
584
719
  return 'native_flow_response';
585
720
  }
586
- else if (message.groupInviteMessage) {
721
+ else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
722
+ return 'cataloglink';
723
+ }
724
+ else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
725
+ return 'productlink';
726
+ }
727
+ else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
587
728
  return 'url';
588
729
  }
589
730
  };
@@ -599,9 +740,8 @@ const makeMessagesSocket = (config) => {
599
740
  }
600
741
  };
601
742
  const getButtonArgs = (message) => {
602
- var _a, _b;
603
743
  const nativeFlow = message.interactiveMessage?.nativeFlowMessage;
604
- const firstButtonName = (_b = (_a = nativeFlow === null || nativeFlow === void 0 ? void 0 : nativeFlow.buttons) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.name;
744
+ const firstButtonName = nativeFlow?.buttons?.[0]?.name;
605
745
  const nativeFlowSpecials = [
606
746
  'mpm', 'cta_catalog', 'send_location',
607
747
  'call_permission_request', 'wa_payment_transaction_details',
@@ -615,8 +755,8 @@ const makeMessagesSocket = (config) => {
615
755
  }
616
756
  };
617
757
  }
618
- if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
619
- // Only works for WhatsApp Original, not WhatsApp Business
758
+ else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
759
+ /** Only works for WhatsApp Original, not WhatsApp Business **/
620
760
  return {
621
761
  tag: 'biz',
622
762
  attrs: {
@@ -646,8 +786,8 @@ const makeMessagesSocket = (config) => {
646
786
  }]
647
787
  };
648
788
  }
649
- if (nativeFlow || message.buttonsMessage) {
650
- // It works for WhatsApp original and WhatsApp business
789
+ else if (nativeFlow || message.buttonsMessage) {
790
+ /** It works for whatsapp original and whatsapp business **/
651
791
  return {
652
792
  tag: 'biz',
653
793
  attrs: {
@@ -677,7 +817,7 @@ const makeMessagesSocket = (config) => {
677
817
  }]
678
818
  };
679
819
  }
680
- if (message.listMessage) {
820
+ else if (message.listMessage) {
681
821
  return {
682
822
  tag: 'biz',
683
823
  attrs: {
@@ -700,14 +840,16 @@ const makeMessagesSocket = (config) => {
700
840
  }]
701
841
  };
702
842
  }
703
- return {
704
- tag: 'biz',
705
- attrs: {
706
- actual_actors: '2',
707
- host_storage: '2',
708
- privacy_mode_ts: (0, Utils_1.unixTimestampSeconds)().toString()
709
- }
710
- };
843
+ else {
844
+ return {
845
+ tag: 'biz',
846
+ attrs: {
847
+ actual_actors: '2',
848
+ host_storage: '2',
849
+ privacy_mode_ts: (0, Utils_1.unixTimestampSeconds)().toString()
850
+ }
851
+ };
852
+ }
711
853
  };
712
854
  const updateMemberLabel = (jid, memberLabel) => relayMessage(jid, {
713
855
  protocolMessage: {
@@ -756,6 +898,30 @@ const makeMessagesSocket = (config) => {
756
898
  return result;
757
899
  };
758
900
  const waUploadToServer = (0, Utils_1.getWAUploadToServer)(config, refreshMediaConn);
901
+ const sendStatusMentions = async (content, jids) => {
902
+ const msg = await (0, Utils_1.generateWAMessage)(WABinary_1.S_WHATSAPP_NET, content, {
903
+ logger,
904
+ userJid: authState.creds.me.id,
905
+ getUrlInfo: text => (0, link_preview_1.getUrlInfo)(text, {
906
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
907
+ fetchOpts: {
908
+ timeout: 3000,
909
+ ...axiosOptions || {}
910
+ },
911
+ logger,
912
+ uploadImage: generateHighQualityLinkPreview
913
+ ? waUploadToServer
914
+ : undefined
915
+ }),
916
+ getProfilePicUrl: profilePictureUrl,
917
+ upload: waUploadToServer,
918
+ mediaCache: config.mediaCache,
919
+ options: config.options
920
+ });
921
+ return relayMessage('status@broadcast', msg.message, {
922
+ statusJidList: jids
923
+ });
924
+ };
759
925
  const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update');
760
926
  return {
761
927
  ...sock,
@@ -773,6 +939,8 @@ const makeMessagesSocket = (config) => {
773
939
  sendPeerDataOperationMessage,
774
940
  updateMemberLabel,
775
941
  messageRetryManager,
942
+ profilePictureUrl,
943
+ sendStatusMentions,
776
944
  updateMediaMessage: async (message) => {
777
945
  const content = (0, Utils_1.assertMediaContent)(message.message);
778
946
  const mediaKey = content.mediaKey;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBinaryNodeMessages = exports.reduceBinaryNodeToDictionary = exports.assertNodeErrorFree = exports.getBinaryNodeChildUInt = exports.getBinaryNodeChildString = exports.getBinaryNodeChildBuffer = exports.getBinaryNodeChild = exports.getAllBinaryNodeChildren = exports.getBinaryNodeChildren = void 0;
3
+ exports.getBinaryFilteredBizBot = exports.getBinaryFilteredButtons = exports.getBinaryNodeMessages = exports.reduceBinaryNodeToDictionary = exports.assertNodeErrorFree = exports.getBinaryNodeChildUInt = exports.getBinaryNodeChildString = exports.getBinaryNodeChildBuffer = exports.getBinaryNodeChild = exports.getAllBinaryNodeChildren = exports.getBinaryNodeChildren = void 0;
4
4
  exports.binaryNodeToString = binaryNodeToString;
5
5
  const boom_1 = require("@hapi/boom");
6
6
  const WAProto_1 = require("../../WAProto");
@@ -79,6 +79,26 @@ const getBinaryNodeMessages = ({ content }) => {
79
79
  return msgs;
80
80
  };
81
81
  exports.getBinaryNodeMessages = getBinaryNodeMessages;
82
+ const getBinaryFilteredButtons = (nodeContent) => {
83
+ if (!Array.isArray(nodeContent)) {
84
+ return false;
85
+ }
86
+ return nodeContent.some(a => {
87
+ var _a, _b, _c;
88
+ return ['native_flow'].includes((_c = (_b = (_a = a === null || a === void 0 ? void 0 : a.content) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c[0].tag) ||
89
+ ['interactive', 'buttons', 'list'].includes((_d = a === null || a === void 0 ? void 0 : a.content) === null || _d === void 0 ? void 0 : _d[0].tag) ||
90
+ ['hsm', 'biz'].includes(a === null || a === void 0 ? void 0 : a.tag);
91
+ var _d;
92
+ });
93
+ };
94
+ exports.getBinaryFilteredButtons = getBinaryFilteredButtons;
95
+ const getBinaryFilteredBizBot = (nodeContent) => {
96
+ if (!Array.isArray(nodeContent)) {
97
+ return false;
98
+ }
99
+ return nodeContent.some(b => (['bot'].includes(b === null || b === void 0 ? void 0 : b.tag) && (b === null || b === void 0 ? void 0 : b.attrs.biz_bot) === '1'));
100
+ };
101
+ exports.getBinaryFilteredBizBot = getBinaryFilteredBizBot;
82
102
  function bufferToUInt(e, t) {
83
103
  let a = 0;
84
104
  for (let i = 0; i < t; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemo-dev/yebail",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },