@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 +84 -8
- package/README.md +6 -2
- package/lib/Socket/messages-send.js +308 -140
- package/lib/WABinary/generic-utils.js +21 -1
- package/package.json +1 -1
package/EXAMPLES.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
#
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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
|
-
|
|
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, {
|
|
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
|
|
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/
|
|
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
|
|
272
|
-
|
|
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
|
-
|
|
275
|
-
const
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
332
|
+
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' };
|
|
302
333
|
}
|
|
303
334
|
const { user, device } = (0, WABinary_1.jidDecode)(participant.jid);
|
|
304
|
-
devices.push({
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const
|
|
364
|
-
if (!
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
371
|
-
|
|
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
|
-
|
|
381
|
-
|
|
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 (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
399
|
-
|
|
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
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const
|
|
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
|
-
|
|
508
|
+
meRecipients.push(jid);
|
|
434
509
|
}
|
|
435
510
|
else {
|
|
436
|
-
|
|
511
|
+
otherRecipients.push(jid);
|
|
437
512
|
}
|
|
438
|
-
|
|
513
|
+
allRecipients.push(jid);
|
|
439
514
|
}
|
|
440
|
-
await assertSessions(
|
|
515
|
+
await assertSessions(allRecipients);
|
|
441
516
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
442
|
-
createParticipantNodes(
|
|
443
|
-
createParticipantNodes(
|
|
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 (
|
|
451
|
-
const peerNode =
|
|
553
|
+
if (additionalAttributes?.['category'] === 'peer') {
|
|
554
|
+
const peerNode = participants[0]?.content?.[0];
|
|
452
555
|
if (peerNode) {
|
|
453
|
-
binaryNodeContent.push(peerNode);
|
|
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
|
-
|
|
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
|
-
|
|
501
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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
|
-
|
|
516
|
-
|
|
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 (
|
|
653
|
+
else if (message.reactionMessage) {
|
|
531
654
|
return 'reaction';
|
|
532
655
|
}
|
|
533
|
-
else if (
|
|
534
|
-
return '
|
|
656
|
+
else if (message.eventMessage) {
|
|
657
|
+
return 'event';
|
|
535
658
|
}
|
|
536
|
-
else if (getMediaType(
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
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++) {
|