@itsliaaa/baileys 0.1.17 โ 0.1.19
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 +125 -8
- package/lib/Defaults/index.js +7 -0
- package/lib/Signal/libsignal.js +4 -0
- package/lib/Signal/lid-mapping.js +6 -0
- package/lib/Socket/chats.js +15 -4
- package/lib/Socket/messages-recv.js +14 -1
- package/lib/Socket/messages-send.js +13 -1
- package/lib/Socket/socket.js +15 -0
- package/lib/Store/make-in-memory-store.js +1 -2
- package/lib/Types/RichType.js +22 -0
- package/lib/Utils/event-buffer.js +17 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/message-retry-manager.js +17 -0
- package/lib/Utils/messages.js +83 -82
- package/lib/Utils/rich-message-utils.js +182 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
# ๐ฑ @itsliaaa/baileys
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@itsliaaa/baileys)
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@itsliaaa/baileys">
|
|
7
|
+
<img src="https://img.shields.io/npm/v/@itsliaaa/baileys?color=FFFFFF&labelColor=red&logo=npm&logoColor=white&style=for-the-badge"/>
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@itsliaaa/baileys">
|
|
10
|
+
<img src="https://img.shields.io/npm/dm/@itsliaaa/baileys?color=FFFFFF&labelColor=red&logo=npm&logoColor=white&style=for-the-badge"/>
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://github.com/itsliaaa/baileys">
|
|
13
|
+
<img src="https://img.shields.io/github/stars/itsliaaa/baileys?color=FFFFFF&labelColor=black&logo=github&logoColor=white&style=for-the-badge"/>
|
|
14
|
+
</a>
|
|
15
|
+
<a href="LICENSE">
|
|
16
|
+
<img src="https://img.shields.io/badge/license-MIT-blue?labelColor=black&style=for-the-badge"/>
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://nodejs.org">
|
|
19
|
+
<img src="https://img.shields.io/badge/node-%3E%3D20-339933?logo=node.js&labelColor=green&logoColor=white&style=for-the-badge"/>
|
|
20
|
+
</a>
|
|
21
|
+
<a href="#">
|
|
22
|
+
<img src="https://img.shields.io/badge/ESM-only?logo=javascript&labelColor=yellow&logoColor=black&style=for-the-badge"/>
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
A lightweight fork of Baileys with practical fixes and small but meaningful improvements.
|
|
27
|
+
|
|
28
|
+
### โจ Highlights
|
|
29
|
+
|
|
30
|
+
This fork focuses on clarity and safety:
|
|
31
|
+
|
|
32
|
+
- ๐ซ No obfuscation. Easy to read and audit.
|
|
33
|
+
- ๐ซ No auto-follow channel (newsletter) behavior.
|
|
6
34
|
|
|
7
35
|
### โ๏ธ Changes
|
|
8
36
|
|
|
@@ -10,12 +38,19 @@ A lightweight fork of Baileys with a few fixes and a small adjustment.
|
|
|
10
38
|
- ๐ผ๏ธ Fixed an issue where media could not be sent to newsletters due to an upstream issue.
|
|
11
39
|
- ๐ Reintroduced [`makeInMemoryStore`](#%EF%B8%8F-implementing-a-data-store) with a minimal ESM adaptation and small adjustments for Baileys v7.
|
|
12
40
|
- ๐ฆ Switched FFmpeg execution from `exec` to `spawn` for safer process handling.
|
|
13
|
-
- ๐๏ธ Added `@napi-rs/image` as a supported image processing backend in `getImageProcessingLibrary()
|
|
41
|
+
- ๐๏ธ Added [`@napi-rs/image`](https://www.npmjs.com/package/@napi-rs/image) as a supported image processing backend in [`getImageProcessingLibrary()`](#%EF%B8%8F-image-processing), offering a balance between performance and compatibility.
|
|
14
42
|
|
|
15
43
|
#### ๐จ Message Handling & Compatibility
|
|
16
|
-
- ๐๐ป Added support for sending [interactive
|
|
17
|
-
- ๐ฉ
|
|
18
|
-
-
|
|
44
|
+
- ๐๐ป Added support for sending [interactive messages](#-sending-interactive-messages) (buttons, lists, interactive, templates, carousel).
|
|
45
|
+
- ๐ฉ Expanded message support for:
|
|
46
|
+
- [album messages](#%EF%B8%8F-album-image--video)
|
|
47
|
+
- [group status messages](#4%EF%B8%8Fโฃ-group-status)
|
|
48
|
+
- [status mention messages](#%EF%B8%8F-status-mention)
|
|
49
|
+
- [sticker pack messages](#-sticker-pack)
|
|
50
|
+
- [messages with code blocks](#-message-with-code-block)
|
|
51
|
+
- [messages with tables](#-message-with-table)
|
|
52
|
+
- [payment-related messages](#-sending-payment-messages) (payment requests, invites, orders, invoices).
|
|
53
|
+
- ๐ฐ Simplified sending messages with ad thumbnails using [`externalAdReply`](#3%EF%B8%8Fโฃ-external-ad-reply), without requiring manual `contextInfo`.
|
|
19
54
|
|
|
20
55
|
#### ๐งฉ Additional Message Options
|
|
21
56
|
- ๐๏ธ Added optional boolean flags for message handling:
|
|
@@ -370,6 +405,32 @@ sock.sendMessage([jidA, jidB, jidC], {
|
|
|
370
405
|
})
|
|
371
406
|
```
|
|
372
407
|
|
|
408
|
+
##### ๐งพ Message with Code Block
|
|
409
|
+
|
|
410
|
+
```javascript
|
|
411
|
+
sock.sendMessage(jid, {
|
|
412
|
+
header: 'Example Usage',
|
|
413
|
+
code: 'console.log("Hello, World!")',
|
|
414
|
+
footer: 'Pretty simple, right?',
|
|
415
|
+
language: 'javascript'
|
|
416
|
+
})
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
##### ๐ Message with Table
|
|
420
|
+
|
|
421
|
+
```javascript
|
|
422
|
+
sock.sendMessage(jid, {
|
|
423
|
+
header: 'Comparison between Node.js, Bun, and Deno',
|
|
424
|
+
title: 'Runtime Comparison',
|
|
425
|
+
table: [
|
|
426
|
+
['', 'Node.js', 'Bun', 'Deno'],
|
|
427
|
+
['Engine', 'V8 (C++)', 'JavaScriptCore (C++)', 'V8 (C++)'],
|
|
428
|
+
['Performance', '4/5', '5/5', '4/5']
|
|
429
|
+
],
|
|
430
|
+
footer: 'Does this help clarify the differences?'
|
|
431
|
+
})
|
|
432
|
+
```
|
|
433
|
+
|
|
373
434
|
#### ๐ Sending Media Messages
|
|
374
435
|
|
|
375
436
|
> [!NOTE]
|
|
@@ -662,7 +723,7 @@ sock.sendMessage(jid, {
|
|
|
662
723
|
caption: '๐ผ๏ธ Image 3',
|
|
663
724
|
footer: '๐ท๏ธ Pinterest',
|
|
664
725
|
optionText: '๐๐ป Select Options',
|
|
665
|
-
optionTitle: '
|
|
726
|
+
optionTitle: '๐๐ป Select Options',
|
|
666
727
|
offerText: '๐ท๏ธ New Coupon!',
|
|
667
728
|
offerCode: '@itsliaaa/baileys',
|
|
668
729
|
offerUrl: 'https://www.npmjs.com/package/@itsliaaa/baileys',
|
|
@@ -959,6 +1020,62 @@ await sock.requestPairingCode(phoneNumber, customPairingCode)
|
|
|
959
1020
|
console.log('๐ Pairing code', ':', customPairingCode)
|
|
960
1021
|
```
|
|
961
1022
|
|
|
1023
|
+
##### ๐ผ๏ธ Image Processing
|
|
1024
|
+
|
|
1025
|
+
> [!NOTE]
|
|
1026
|
+
Automatically use available image processing library: `sharp`, `@napi-rs/image`, or `jimp`
|
|
1027
|
+
|
|
1028
|
+
```javascript
|
|
1029
|
+
import { getImageProcessingLibrary } from '@itsliaaa/baileys'
|
|
1030
|
+
import { readFile } from 'fs/promises'
|
|
1031
|
+
|
|
1032
|
+
const lib = await getImageProcessingLibrary()
|
|
1033
|
+
|
|
1034
|
+
const bufferOrFilePath = './path/to/image.jpg'
|
|
1035
|
+
const width = 512
|
|
1036
|
+
|
|
1037
|
+
let output
|
|
1038
|
+
|
|
1039
|
+
// --- If sharp installed
|
|
1040
|
+
if (lib.sharp?.default) {
|
|
1041
|
+
const img = lib.sharp.default(bufferOrFilePath)
|
|
1042
|
+
|
|
1043
|
+
output = await img.resize(width)
|
|
1044
|
+
.jpeg({ quality: 80 })
|
|
1045
|
+
.toBuffer()
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
// --- If @napi-rs/image installed
|
|
1049
|
+
else if (lib.image?.Transformer) {
|
|
1050
|
+
// --- Must in buffer format
|
|
1051
|
+
const inputBuffer = Buffer.isBuffer(bufferOrFilePath)
|
|
1052
|
+
? bufferOrFilePath
|
|
1053
|
+
: await readFile(bufferOrFilePath)
|
|
1054
|
+
|
|
1055
|
+
const img = new lib.image.Transformer(inputBuffer)
|
|
1056
|
+
|
|
1057
|
+
output = await img.resize(width, undefined, 0)
|
|
1058
|
+
.jpeg(50)
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// --- If jimp installed
|
|
1062
|
+
else if (lib.jimp?.Jimp) {
|
|
1063
|
+
const img = await lib.jimp.Jimp.read(bufferOrFilePath)
|
|
1064
|
+
|
|
1065
|
+
output = await img
|
|
1066
|
+
.resize({ w: width, mode: lib.jimp.ResizeStrategy.BILINEAR })
|
|
1067
|
+
.getBuffer('image/jpeg', { quality: 50 });
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// --- Fallback
|
|
1071
|
+
else {
|
|
1072
|
+
throw new Error('No image processing available')
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
console.log('โ
Process completed!')
|
|
1076
|
+
console.dir(output, { depth: null })
|
|
1077
|
+
```
|
|
1078
|
+
|
|
962
1079
|
##### ๐ฃ Newsletter Management
|
|
963
1080
|
|
|
964
1081
|
```javascript
|
package/lib/Defaults/index.js
CHANGED
|
@@ -26,6 +26,7 @@ export const NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0';
|
|
|
26
26
|
export const DICT_VERSION = 3;
|
|
27
27
|
export const KEY_BUNDLE_TYPE = Buffer.from([5]);
|
|
28
28
|
export const NOISE_WA_HEADER = Buffer.from([87, 65, 6, DICT_VERSION]); // last is "DICT_VERSION"
|
|
29
|
+
export const LEXER_REGEX = /(\/\/.*|\/\*[\s\S]*?\*\/|#.*)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`[\s\S]*?`)|(\b[a-zA-Z_]\w*\b)(?=\s*\()|(\b[a-zA-Z_]\w*\b)|(\b\d+(?:\.\d+)?\b)|(\s+|[^\w\s]+)/g;
|
|
29
30
|
/** from: https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url */
|
|
30
31
|
export const URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g;
|
|
31
32
|
export const WA_CERT_DETAILS = {
|
|
@@ -140,4 +141,10 @@ export const TimeMs = {
|
|
|
140
141
|
Hour: 60 * 60 * 1000,
|
|
141
142
|
Day: 24 * 60 * 60 * 1000,
|
|
142
143
|
Week: 7 * 24 * 60 * 60 * 1000
|
|
144
|
+
};
|
|
145
|
+
export const FORWARDED_AI_BOT_INFO = {
|
|
146
|
+
isForwarded: true,
|
|
147
|
+
forwardingScore: 1,
|
|
148
|
+
forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' },
|
|
149
|
+
forwardOrigin: 4
|
|
143
150
|
};
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -171,6 +171,10 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
171
171
|
await auth.keys.set({ session: sessionUpdates });
|
|
172
172
|
}, `delete-${jids.length}-sessions`);
|
|
173
173
|
},
|
|
174
|
+
close () {
|
|
175
|
+
migratedSessionCache.clear();
|
|
176
|
+
lidMapping.close();
|
|
177
|
+
},
|
|
174
178
|
async migrateSession(fromJid, toJid) {
|
|
175
179
|
// TODO: use usync to handle this entire mess
|
|
176
180
|
if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid)))
|
package/lib/Socket/chats.js
CHANGED
|
@@ -17,7 +17,7 @@ const USER_ID_CACHE = new Map();
|
|
|
17
17
|
export const makeChatsSocket = (config) => {
|
|
18
18
|
const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
|
|
19
19
|
const sock = makeSocket(config);
|
|
20
|
-
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
|
|
20
|
+
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession, registerSocketEndHandler } = sock;
|
|
21
21
|
let privacySettings;
|
|
22
22
|
let syncState = SyncState.Connecting;
|
|
23
23
|
/** this mutex ensures that messages are processed in order */
|
|
@@ -35,9 +35,9 @@ export const makeChatsSocket = (config) => {
|
|
|
35
35
|
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
36
36
|
useClones: false
|
|
37
37
|
});
|
|
38
|
-
if (!config.placeholderResendCache) {
|
|
39
|
-
|
|
40
|
-
}
|
|
38
|
+
// if (!config.placeholderResendCache) {
|
|
39
|
+
// config.placeholderResendCache = placeholderResendCache;
|
|
40
|
+
// }
|
|
41
41
|
/** helper function to fetch the given app state sync key */
|
|
42
42
|
const getAppStateSyncKey = async (keyId) => {
|
|
43
43
|
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
|
|
@@ -997,6 +997,17 @@ export const makeChatsSocket = (config) => {
|
|
|
997
997
|
logger.warn({ lid, pn, error }, 'Failed to store LID-PN mapping');
|
|
998
998
|
}
|
|
999
999
|
});
|
|
1000
|
+
registerSocketEndHandler(() => {
|
|
1001
|
+
if (awaitingSyncTimeout) {
|
|
1002
|
+
clearTimeout(awaitingSyncTimeout);
|
|
1003
|
+
awaitingSyncTimeout = undefined;
|
|
1004
|
+
}
|
|
1005
|
+
if (!config.placeholderResendCache && placeholderResendCache.close) {
|
|
1006
|
+
placeholderResendCache.close();
|
|
1007
|
+
}
|
|
1008
|
+
syncState = SyncState.Connecting;
|
|
1009
|
+
privacySettings = undefined;
|
|
1010
|
+
});
|
|
1000
1011
|
return {
|
|
1001
1012
|
...sock,
|
|
1002
1013
|
createCallLink,
|
|
@@ -15,7 +15,7 @@ import { makeMessagesSocket } from './messages-send.js';
|
|
|
15
15
|
export const makeMessagesRecvSocket = (config) => {
|
|
16
16
|
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid, enableAutoSessionRecreation } = config;
|
|
17
17
|
const sock = makeMessagesSocket(config);
|
|
18
|
-
const { ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, generateMessageTag, messageRetryManager } = sock;
|
|
18
|
+
const { ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, generateMessageTag, messageRetryManager, registerSocketEndHandler } = sock;
|
|
19
19
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
20
20
|
const retryMutex = makeMutex();
|
|
21
21
|
const devicesMutex = makeMutex();
|
|
@@ -1449,6 +1449,19 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1449
1449
|
logger.trace(`sendActiveReceipts set to "${sendActiveReceipts}"`);
|
|
1450
1450
|
}
|
|
1451
1451
|
});
|
|
1452
|
+
registerSocketEndHandler(() => {
|
|
1453
|
+
if (!config.msgRetryCounterCache && msgRetryCache.close) {
|
|
1454
|
+
msgRetryCache.close();
|
|
1455
|
+
}
|
|
1456
|
+
if (!config.callOfferCache && callOfferCache.close) {
|
|
1457
|
+
callOfferCache.close();
|
|
1458
|
+
}
|
|
1459
|
+
if (!config.placeholderResendCache && placeholderResendCache.close) {
|
|
1460
|
+
placeholderResendCache.close();
|
|
1461
|
+
}
|
|
1462
|
+
identityAssertDebounce.close();
|
|
1463
|
+
sendActiveReceipts = false;
|
|
1464
|
+
});
|
|
1452
1465
|
return {
|
|
1453
1466
|
...sock,
|
|
1454
1467
|
sendMessageAck,
|
|
@@ -14,7 +14,7 @@ import { makeNewsletterSocket } from './newsletter.js';
|
|
|
14
14
|
export const makeMessagesSocket = (config) => {
|
|
15
15
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
16
16
|
const sock = makeNewsletterSocket(config);
|
|
17
|
-
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
|
|
17
|
+
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, registerSocketEndHandler } = sock;
|
|
18
18
|
const userDevicesCache = config.userDevicesCache ??=
|
|
19
19
|
new NodeCache({
|
|
20
20
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
@@ -939,6 +939,18 @@ export const makeMessagesSocket = (config) => {
|
|
|
939
939
|
};
|
|
940
940
|
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
941
941
|
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
942
|
+
registerSocketEndHandler(() => {
|
|
943
|
+
if (!config.userDevicesCache && userDevicesCache.close) {
|
|
944
|
+
userDevicesCache.close();
|
|
945
|
+
}
|
|
946
|
+
if (peerSessionsCache.close) {
|
|
947
|
+
peerSessionsCache.close();
|
|
948
|
+
}
|
|
949
|
+
mediaConn = undefined;
|
|
950
|
+
if (messageRetryManager) {
|
|
951
|
+
messageRetryManager.clear();
|
|
952
|
+
}
|
|
953
|
+
});
|
|
942
954
|
return {
|
|
943
955
|
...sock,
|
|
944
956
|
getPrivacyTokens,
|
package/lib/Socket/socket.js
CHANGED
|
@@ -269,6 +269,7 @@ export const makeSocket = (config) => {
|
|
|
269
269
|
let keepAliveReq;
|
|
270
270
|
let qrTimer;
|
|
271
271
|
let closed = false;
|
|
272
|
+
const socketEndHandlers = [];
|
|
272
273
|
/** log & process any unexpected errors */
|
|
273
274
|
const onUnexpectedError = (err, msg) => {
|
|
274
275
|
logger.error({ err }, `unexpected error in '${msg}'`);
|
|
@@ -485,12 +486,21 @@ export const makeSocket = (config) => {
|
|
|
485
486
|
ws.removeAllListeners('close');
|
|
486
487
|
ws.removeAllListeners('open');
|
|
487
488
|
ws.removeAllListeners('message');
|
|
489
|
+
signalRepository.close?.();
|
|
488
490
|
if (!ws.isClosed && !ws.isClosing) {
|
|
489
491
|
try {
|
|
490
492
|
await ws.close();
|
|
491
493
|
}
|
|
492
494
|
catch { }
|
|
493
495
|
}
|
|
496
|
+
for (const handler of socketEndHandlers) {
|
|
497
|
+
try {
|
|
498
|
+
handler(error);
|
|
499
|
+
}
|
|
500
|
+
catch (err) {
|
|
501
|
+
logger.error({ err }, 'error in socket end handler');
|
|
502
|
+
}
|
|
503
|
+
}
|
|
494
504
|
ev.emit('connection.update', {
|
|
495
505
|
connection: 'close',
|
|
496
506
|
lastDisconnect: {
|
|
@@ -499,6 +509,7 @@ export const makeSocket = (config) => {
|
|
|
499
509
|
}
|
|
500
510
|
});
|
|
501
511
|
ev.removeAllListeners('connection.update');
|
|
512
|
+
ev.destroy();
|
|
502
513
|
};
|
|
503
514
|
const waitForSocketOpen = async () => {
|
|
504
515
|
if (ws.isOpen) {
|
|
@@ -890,6 +901,9 @@ export const makeSocket = (config) => {
|
|
|
890
901
|
logger.debug({ error }, 'failed to send unified_session telemetry');
|
|
891
902
|
}
|
|
892
903
|
};
|
|
904
|
+
const registerSocketEndHandler = (handler) => {
|
|
905
|
+
socketEndHandlers.push(handler);
|
|
906
|
+
}
|
|
893
907
|
return {
|
|
894
908
|
type: 'md',
|
|
895
909
|
ws,
|
|
@@ -907,6 +921,7 @@ export const makeSocket = (config) => {
|
|
|
907
921
|
sendNode,
|
|
908
922
|
logout,
|
|
909
923
|
end,
|
|
924
|
+
registerSocketEndHandler,
|
|
910
925
|
onUnexpectedError,
|
|
911
926
|
uploadPreKeys,
|
|
912
927
|
uploadPreKeysToServerIfRequired,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export var CodeHighlightType;
|
|
2
|
+
(function (CodeHighlightType) {
|
|
3
|
+
CodeHighlightType[CodeHighlightType["DEFAULT"] = 0] = "DEFAULT";
|
|
4
|
+
CodeHighlightType[CodeHighlightType["KEYWORD"] = 1] = "KEYWORD";
|
|
5
|
+
CodeHighlightType[CodeHighlightType["METHOD"] = 2] = "METHOD";
|
|
6
|
+
CodeHighlightType[CodeHighlightType["STRING"] = 3] = "STRING";
|
|
7
|
+
CodeHighlightType[CodeHighlightType["NUMBER"] = 4] = "NUMBER";
|
|
8
|
+
CodeHighlightType[CodeHighlightType["COMMENT"] = 5] = "COMMENT";
|
|
9
|
+
})(CodeHighlightType || (CodeHighlightType = {}));
|
|
10
|
+
export var RichSubMessageType;
|
|
11
|
+
(function (RichSubMessageType) {
|
|
12
|
+
RichSubMessageType[RichSubMessageType["UNKNOWN"] = 0] = "UNKNOWN";
|
|
13
|
+
RichSubMessageType[RichSubMessageType["GRID_IMAGE"] = 1] = "GRID_IMAGE";
|
|
14
|
+
RichSubMessageType[RichSubMessageType["TEXT"] = 2] = "TEXT";
|
|
15
|
+
RichSubMessageType[RichSubMessageType["INLINE_IMAGE"] = 3] = "INLINE_IMAGE";
|
|
16
|
+
RichSubMessageType[RichSubMessageType["TABLE"] = 4] = "TABLE";
|
|
17
|
+
RichSubMessageType[RichSubMessageType["CODE"] = 5] = "CODE";
|
|
18
|
+
RichSubMessageType[RichSubMessageType["DYNAMIC"] = 6] = "DYNAMIC";
|
|
19
|
+
RichSubMessageType[RichSubMessageType["MAP"] = 7] = "MAP";
|
|
20
|
+
RichSubMessageType[RichSubMessageType["LATEX"] = 8] = "LATEX";
|
|
21
|
+
RichSubMessageType[RichSubMessageType["CONTENT_ITEMS"] = 9] = "CONTENT_ITEMS";
|
|
22
|
+
})(RichSubMessageType || (RichSubMessageType = {}));
|
|
@@ -169,7 +169,23 @@ export const makeEventBuffer = (logger) => {
|
|
|
169
169
|
},
|
|
170
170
|
on: (...args) => ev.on(...args),
|
|
171
171
|
off: (...args) => ev.off(...args),
|
|
172
|
-
removeAllListeners: (...args) => ev.removeAllListeners(...args)
|
|
172
|
+
removeAllListeners: (...args) => ev.removeAllListeners(...args),
|
|
173
|
+
destroy() {
|
|
174
|
+
// Clear buffer timeout
|
|
175
|
+
if (bufferTimeout) {
|
|
176
|
+
clearTimeout(bufferTimeout);
|
|
177
|
+
bufferTimeout = null;
|
|
178
|
+
}
|
|
179
|
+
// Clear history cache
|
|
180
|
+
historyCache.clear();
|
|
181
|
+
// Reset buffer data
|
|
182
|
+
data = makeBufferData();
|
|
183
|
+
isBuffering = false;
|
|
184
|
+
bufferCount = 0;
|
|
185
|
+
// Remove all listeners
|
|
186
|
+
ev.removeAllListeners();
|
|
187
|
+
logger.debug('Event buffer destroyed');
|
|
188
|
+
}
|
|
173
189
|
};
|
|
174
190
|
};
|
|
175
191
|
const makeBufferData = () => {
|
package/lib/Utils/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './generics.js';
|
|
|
2
2
|
export * from './decode-wa-message.js';
|
|
3
3
|
export * from './messages.js';
|
|
4
4
|
export * from './messages-media.js';
|
|
5
|
+
export * from './rich-message-utils.js';
|
|
5
6
|
export * from './validate-connection.js';
|
|
6
7
|
export * from './crypto.js';
|
|
7
8
|
export * from './signal.js';
|
|
@@ -210,6 +210,23 @@ export class MessageRetryManager {
|
|
|
210
210
|
this.logger.debug(`Cancelled pending phone request for message ${messageId}`);
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
+
clear() {
|
|
214
|
+
this.recentMessagesMap.clear();
|
|
215
|
+
this.messageKeyIndex.clear();
|
|
216
|
+
this.sessionRecreateHistory.clear();
|
|
217
|
+
this.retryCounters.clear();
|
|
218
|
+
for (const messageId of Object.keys(this.pendingPhoneRequests)) {
|
|
219
|
+
this.cancelPendingPhoneRequest(messageId);
|
|
220
|
+
}
|
|
221
|
+
this.statistics = {
|
|
222
|
+
totalRetries: 0,
|
|
223
|
+
successfulRetries: 0,
|
|
224
|
+
failedRetries: 0,
|
|
225
|
+
mediaRetries: 0,
|
|
226
|
+
sessionRecreations: 0,
|
|
227
|
+
phoneRequests: 0
|
|
228
|
+
};
|
|
229
|
+
}
|
|
213
230
|
keyToString(key) {
|
|
214
231
|
return `${key.to}${MESSAGE_KEY_SEPARATOR}${key.id}`;
|
|
215
232
|
}
|
package/lib/Utils/messages.js
CHANGED
|
@@ -10,6 +10,7 @@ import { isPnUser, isLidUser, isJidGroup, isJidNewsletter, isJidStatusBroadcast,
|
|
|
10
10
|
import { sha256 } from './crypto.js';
|
|
11
11
|
import { generateMessageIDV2, getKeyAuthor, unixTimestampSeconds } from './generics.js';
|
|
12
12
|
import { downloadContentFromMessage, encryptedStream, generateThumbnail, getAudioDuration, getAudioWaveform, getImageProcessingLibrary, getRawMediaUploadData, getStream, toBuffer } from './messages-media.js';
|
|
13
|
+
import { generateRichCodeBlock, generateRichTable, wrapToBotForwardedMessage } from './rich-message-utils.js';
|
|
13
14
|
import { shouldIncludeReportingToken } from './reporting-utils.js';
|
|
14
15
|
const MIMETYPE_MAP = {
|
|
15
16
|
image: 'image/jpeg',
|
|
@@ -692,7 +693,7 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
692
693
|
// Lia@Changes 30-01-26 --- Add "raw" boolean to send raw messages directly via generateWAMessage()
|
|
693
694
|
if (hasNonNullishProperty(message, 'raw')) {
|
|
694
695
|
delete message.raw;
|
|
695
|
-
return
|
|
696
|
+
return message;
|
|
696
697
|
}
|
|
697
698
|
else if (hasNonNullishProperty(message, 'text')) {
|
|
698
699
|
const extContent = { text: message.text };
|
|
@@ -726,27 +727,25 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
726
727
|
m.extendedTextMessage = extContent;
|
|
727
728
|
}
|
|
728
729
|
else if (hasNonNullishProperty(message, 'contacts')) {
|
|
729
|
-
const
|
|
730
|
-
const contactLen = contacts.contacts.length;
|
|
730
|
+
const contactLen = message.contacts.contacts.length;
|
|
731
731
|
if (!contactLen) {
|
|
732
732
|
throw new Boom('require atleast 1 contact', { statusCode: 400 });
|
|
733
733
|
}
|
|
734
734
|
if (contactLen === 1) {
|
|
735
|
-
m.contactMessage = contacts.contacts[0];
|
|
735
|
+
m.contactMessage = message.contacts.contacts[0];
|
|
736
736
|
}
|
|
737
737
|
else {
|
|
738
|
-
m.contactsArrayMessage = contacts;
|
|
738
|
+
m.contactsArrayMessage = message.contacts;
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
741
|
else if (hasNonNullishProperty(message, 'location')) {
|
|
742
742
|
m.locationMessage = message.location;
|
|
743
743
|
}
|
|
744
744
|
else if (hasNonNullishProperty(message, 'react')) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
react.senderTimestampMs = Date.now();
|
|
745
|
+
if (!message.react.senderTimestampMs) {
|
|
746
|
+
message.react.senderTimestampMs = Date.now();
|
|
748
747
|
}
|
|
749
|
-
m.reactionMessage = react;
|
|
748
|
+
m.reactionMessage = message.react;
|
|
750
749
|
}
|
|
751
750
|
else if (hasNonNullishProperty(message, 'delete')) {
|
|
752
751
|
m.protocolMessage = {
|
|
@@ -758,26 +757,24 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
758
757
|
m = generateForwardMessageContent(message.forward, message.force);
|
|
759
758
|
}
|
|
760
759
|
else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) {
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
? disappearingMessagesInChat
|
|
760
|
+
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
761
|
+
? message.disappearingMessagesInChat
|
|
764
762
|
? WA_DEFAULT_EPHEMERAL
|
|
765
763
|
: 0
|
|
766
|
-
: disappearingMessagesInChat;
|
|
764
|
+
: message.disappearingMessagesInChat;
|
|
767
765
|
m = prepareDisappearingMessageSettingContent(exp);
|
|
768
766
|
}
|
|
769
767
|
else if (hasNonNullishProperty(message, 'groupInvite')) {
|
|
770
|
-
const { groupInvite } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (โ โทโ โฟโ โทโ )
|
|
771
768
|
m.groupInviteMessage = {};
|
|
772
|
-
m.groupInviteMessage.inviteCode = groupInvite.inviteCode;
|
|
773
|
-
m.groupInviteMessage.inviteExpiration = groupInvite.inviteExpiration;
|
|
774
|
-
m.groupInviteMessage.caption = groupInvite.text;
|
|
775
|
-
m.groupInviteMessage.groupJid = groupInvite.jid;
|
|
776
|
-
m.groupInviteMessage.groupName = groupInvite.subject;
|
|
769
|
+
m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
|
|
770
|
+
m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
|
|
771
|
+
m.groupInviteMessage.caption = message.groupInvite.text;
|
|
772
|
+
m.groupInviteMessage.groupJid = message.groupInvite.jid;
|
|
773
|
+
m.groupInviteMessage.groupName = message.groupInvite.subject;
|
|
777
774
|
//TODO: use built-in interface and get disappearing mode info etc.
|
|
778
775
|
//TODO: cache / use store!?
|
|
779
776
|
if (options.getProfilePicUrl) {
|
|
780
|
-
const pfpUrl = await options.getProfilePicUrl(groupInvite.jid, 'preview');
|
|
777
|
+
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
|
|
781
778
|
if (pfpUrl) {
|
|
782
779
|
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
|
|
783
780
|
if (resp.ok) {
|
|
@@ -805,47 +802,44 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
805
802
|
m.keepInChatMessage.timestampMs = Date.now();
|
|
806
803
|
}
|
|
807
804
|
else if (hasNonNullishProperty(message, 'flowReply')) {
|
|
808
|
-
const { flowReply } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (โ โทโ โฟโ โทโ )
|
|
809
805
|
m.interactiveResponseMessage = {
|
|
810
806
|
body: {
|
|
811
|
-
format: flowReply.format || proto.Message.InteractiveResponseMessage.Body.Format.DEFAULT,
|
|
812
|
-
text: flowReply.text
|
|
807
|
+
format: message.flowReply.format || proto.Message.InteractiveResponseMessage.Body.Format.DEFAULT,
|
|
808
|
+
text: message.flowReply.text
|
|
813
809
|
},
|
|
814
810
|
nativeFlowResponseMessage: {
|
|
815
|
-
name: flowReply.name,
|
|
816
|
-
paramsJson: flowReply.paramsJson || '{}',
|
|
817
|
-
version: flowReply.version || 1
|
|
811
|
+
name: message.flowReply.name,
|
|
812
|
+
paramsJson: message.flowReply.paramsJson || '{}',
|
|
813
|
+
version: message.flowReply.version || 1
|
|
818
814
|
}
|
|
819
815
|
};
|
|
820
816
|
}
|
|
821
817
|
else if (hasNonNullishProperty(message, 'buttonReply')) {
|
|
822
|
-
const { buttonReply } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (โ โทโ โฟโ โทโ )
|
|
823
818
|
switch (message.type) {
|
|
824
819
|
case 'template':
|
|
825
820
|
m.templateButtonReplyMessage = {
|
|
826
|
-
selectedDisplayText: buttonReply.displayText,
|
|
827
|
-
selectedId: buttonReply.id,
|
|
828
|
-
selectedIndex: buttonReply.index
|
|
821
|
+
selectedDisplayText: message.buttonReply.displayText,
|
|
822
|
+
selectedId: message.buttonReply.id,
|
|
823
|
+
selectedIndex: message.buttonReply.index
|
|
829
824
|
};
|
|
830
825
|
break;
|
|
831
826
|
case 'plain':
|
|
832
827
|
m.buttonsResponseMessage = {
|
|
833
|
-
selectedButtonId: buttonReply.id,
|
|
834
|
-
selectedDisplayText: buttonReply.displayText,
|
|
828
|
+
selectedButtonId: message.buttonReply.id,
|
|
829
|
+
selectedDisplayText: message.buttonReply.displayText,
|
|
835
830
|
type: proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
|
|
836
831
|
};
|
|
837
832
|
break;
|
|
838
833
|
}
|
|
839
834
|
}
|
|
840
835
|
else if (hasNonNullishProperty(message, 'listReply')) {
|
|
841
|
-
const { listReply } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (โ โทโ โฟโ โทโ )
|
|
842
836
|
m.listResponseMessage = {
|
|
843
|
-
description: listReply.description,
|
|
837
|
+
description: message.listReply.description,
|
|
844
838
|
listType: proto.Message.ListResponseMessage.ListType.SINGLE_SELECT,
|
|
845
839
|
singleSelectReply: {
|
|
846
|
-
selectedRowId: listReply.id
|
|
840
|
+
selectedRowId: message.listReply.id
|
|
847
841
|
},
|
|
848
|
-
title: listReply.title
|
|
842
|
+
title: message.listReply.title
|
|
849
843
|
};
|
|
850
844
|
}
|
|
851
845
|
else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
|
|
@@ -856,68 +850,66 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
856
850
|
m.productMessage = await prepareProductMessage(message, options);
|
|
857
851
|
}
|
|
858
852
|
else if (hasNonNullishProperty(message, 'event')) {
|
|
859
|
-
const { event } = message; // Lia@Changes 04-02-26 --- Destructured for readability & cleaner access (โ โทโ โฟโ โทโ )
|
|
860
853
|
m.eventMessage = {};
|
|
861
|
-
const startTime = Math.floor(event.startDate.getTime() / 1000);
|
|
862
|
-
if (event.call && options.getCallLink) {
|
|
863
|
-
const token = await options.getCallLink(event.call, { startTime });
|
|
864
|
-
m.eventMessage.joinLink = (event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
|
|
854
|
+
const startTime = Math.floor(message.event.startDate.getTime() / 1000);
|
|
855
|
+
if (message.event.call && options.getCallLink) {
|
|
856
|
+
const token = await options.getCallLink(message.event.call, { startTime });
|
|
857
|
+
m.eventMessage.joinLink = (message.event.call === 'audio' ? CALL_AUDIO_PREFIX : CALL_VIDEO_PREFIX) + token;
|
|
865
858
|
}
|
|
866
859
|
m.messageContextInfo = {
|
|
867
860
|
// encKey
|
|
868
|
-
messageSecret: event.messageSecret || randomBytes(32)
|
|
861
|
+
messageSecret: message.event.messageSecret || randomBytes(32)
|
|
869
862
|
};
|
|
870
|
-
m.eventMessage.name = event.name;
|
|
871
|
-
m.eventMessage.description = event.description;
|
|
863
|
+
m.eventMessage.name = message.event.name;
|
|
864
|
+
m.eventMessage.description = message.event.description;
|
|
872
865
|
m.eventMessage.startTime = startTime;
|
|
873
|
-
m.eventMessage.endTime = event.endDate ? event.endDate.getTime() / 1000 : undefined;
|
|
874
|
-
m.eventMessage.isCanceled = event.isCancelled ?? false;
|
|
875
|
-
m.eventMessage.extraGuestsAllowed = event.extraGuestsAllowed;
|
|
876
|
-
m.eventMessage.isScheduleCall = event.isScheduleCall ?? false;
|
|
877
|
-
m.eventMessage.location = event.location;
|
|
866
|
+
m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
|
|
867
|
+
m.eventMessage.isCanceled = message.event.isCancelled ?? false;
|
|
868
|
+
m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
|
|
869
|
+
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
|
|
870
|
+
m.eventMessage.location = message.event.location;
|
|
878
871
|
}
|
|
879
872
|
else if (hasNonNullishProperty(message, 'poll')) {
|
|
880
|
-
|
|
881
|
-
(
|
|
882
|
-
(
|
|
883
|
-
if (!Array.isArray(poll.values)) {
|
|
873
|
+
(_a = message.poll).selectableCount || (_a.selectableCount = 0);
|
|
874
|
+
(_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
875
|
+
if (!Array.isArray(message.poll.values)) {
|
|
884
876
|
throw new Boom('Invalid poll values', { statusCode: 400 });
|
|
885
877
|
}
|
|
886
|
-
if (poll.selectableCount < 0 || poll.selectableCount > poll.values.length) {
|
|
887
|
-
throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${poll.values.length}`, {
|
|
878
|
+
if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
|
|
879
|
+
throw new Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
|
|
888
880
|
statusCode: 400
|
|
889
881
|
});
|
|
890
882
|
}
|
|
891
883
|
m.messageContextInfo = {
|
|
892
884
|
// encKey
|
|
893
|
-
messageSecret: poll.messageSecret || randomBytes(32)
|
|
885
|
+
messageSecret: message.poll.messageSecret || randomBytes(32)
|
|
894
886
|
};
|
|
895
887
|
const pollCreationMessage = {
|
|
896
|
-
name: poll.name,
|
|
897
|
-
selectableOptionsCount: poll.selectableCount,
|
|
898
|
-
options: poll.values.map(optionName => ({ optionName }))
|
|
888
|
+
name: message.poll.name,
|
|
889
|
+
selectableOptionsCount: message.poll.selectableCount,
|
|
890
|
+
options: message.poll.values.map(optionName => ({ optionName }))
|
|
899
891
|
};
|
|
900
|
-
if (poll.toAnnouncementGroup) {
|
|
892
|
+
if (message.poll.toAnnouncementGroup) {
|
|
901
893
|
// poll v2 is for community announcement groups (single select and multiple)
|
|
902
894
|
m.pollCreationMessageV2 = pollCreationMessage;
|
|
903
895
|
}
|
|
904
896
|
else {
|
|
905
897
|
// Lia@Changes 08-02-26 --- Add quiz message support
|
|
906
|
-
if (poll.pollType
|
|
907
|
-
if (!poll.correctAnswer) {
|
|
898
|
+
if (message.poll.pollType == 1) {
|
|
899
|
+
if (!message.poll.correctAnswer) {
|
|
908
900
|
throw new Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
|
|
909
901
|
}
|
|
910
902
|
m.pollCreationMessageV5 = {
|
|
911
903
|
// Lia@Note 08-02-26 --- quiz for newsletter only
|
|
912
904
|
...pollCreationMessage,
|
|
913
905
|
correctAnswer: {
|
|
914
|
-
optionName: poll.correctAnswer.toString()
|
|
906
|
+
optionName: message.poll.correctAnswer.toString()
|
|
915
907
|
},
|
|
916
|
-
pollType: poll.pollType,
|
|
908
|
+
pollType: message.poll.pollType,
|
|
917
909
|
selectableOptionsCount: 1
|
|
918
910
|
};
|
|
919
911
|
}
|
|
920
|
-
else if (poll.selectableCount === 1) {
|
|
912
|
+
else if (message.poll.selectableCount === 1) {
|
|
921
913
|
//poll v3 is for single select polls
|
|
922
914
|
m.pollCreationMessageV3 = pollCreationMessage;
|
|
923
915
|
}
|
|
@@ -929,15 +921,14 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
929
921
|
}
|
|
930
922
|
// Lia@Changes 08-02-26 --- Add poll result snapshot message
|
|
931
923
|
else if (hasNonNullishProperty(message, 'pollResult')) {
|
|
932
|
-
const { pollResult } = message;
|
|
933
924
|
const pollResultSnapshotMessage = {
|
|
934
|
-
name: pollResult.name,
|
|
935
|
-
pollVotes: pollResult.votes.map(vote => ({
|
|
925
|
+
name: message.pollResult.name,
|
|
926
|
+
pollVotes: message.pollResult.votes.map(vote => ({
|
|
936
927
|
optionName: vote.name,
|
|
937
928
|
optionVoteCount: parseInt(vote.voteCount)
|
|
938
929
|
}))
|
|
939
930
|
};
|
|
940
|
-
if (pollResult.pollType
|
|
931
|
+
if (message.pollResult.pollType == 1) {
|
|
941
932
|
pollResultSnapshotMessage.pollType = proto.Message.PollType.QUIZ;
|
|
942
933
|
m.pollResultSnapshotMessageV3 = pollResultSnapshotMessage;
|
|
943
934
|
}
|
|
@@ -948,18 +939,17 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
948
939
|
}
|
|
949
940
|
// Lia@Changes 08-02-26 --- Add poll update message
|
|
950
941
|
else if (hasNonNullishProperty(message, 'pollUpdate')) {
|
|
951
|
-
|
|
952
|
-
if (!pollUpdate.key) {
|
|
942
|
+
if (!message.pollUpdate.key) {
|
|
953
943
|
throw new Boom('Message key is required', { statusCode: 400 });
|
|
954
944
|
}
|
|
955
|
-
if (!pollUpdate.vote) {
|
|
945
|
+
if (!message.pollUpdate.vote) {
|
|
956
946
|
throw new Boom('Encrypted vote payload is required', { statusCode: 400 });
|
|
957
947
|
}
|
|
958
948
|
m.pollUpdateMessage = {
|
|
959
|
-
metadata: pollUpdate.metadata,
|
|
960
|
-
pollCreationMessageKey: pollUpdate.key,
|
|
949
|
+
metadata: message.pollUpdate.metadata,
|
|
950
|
+
pollCreationMessageKey: message.pollUpdate.key,
|
|
961
951
|
senderTimestampMs: Date.now(),
|
|
962
|
-
vote: pollUpdate.vote
|
|
952
|
+
vote: message.pollUpdate.vote
|
|
963
953
|
};
|
|
964
954
|
}
|
|
965
955
|
else if (hasNonNullishProperty(message, 'sharePhoneNumber')) {
|
|
@@ -1009,17 +999,16 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1009
999
|
}
|
|
1010
1000
|
// Lia@Changes 31-01-26 --- Add support for album messages
|
|
1011
1001
|
else if (hasNonNullishProperty(message, 'album')) {
|
|
1012
|
-
|
|
1013
|
-
if (!Array.isArray(album)) {
|
|
1002
|
+
if (!Array.isArray(message.album)) {
|
|
1014
1003
|
throw new Boom('Invalid album type. Expected an array.', { statusCode: 400 });
|
|
1015
1004
|
}
|
|
1016
1005
|
let videoCount = 0;
|
|
1017
|
-
for (let i = 0; i < album.length; i++) {
|
|
1018
|
-
if (album[i].video) videoCount++;
|
|
1006
|
+
for (let i = 0; i < message.album.length; i++) {
|
|
1007
|
+
if (message.album[i].video) videoCount++;
|
|
1019
1008
|
};
|
|
1020
1009
|
let imageCount = 0;
|
|
1021
|
-
for (let i = 0; i < album.length; i++) {
|
|
1022
|
-
if (album[i].image) imageCount++;
|
|
1010
|
+
for (let i = 0; i < message.album.length; i++) {
|
|
1011
|
+
if (message.album[i].image) imageCount++;
|
|
1023
1012
|
};
|
|
1024
1013
|
if ((videoCount + imageCount) < 2) {
|
|
1025
1014
|
throw new Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
|
|
@@ -1029,6 +1018,13 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1029
1018
|
expectedVideoCount: videoCount
|
|
1030
1019
|
};
|
|
1031
1020
|
}
|
|
1021
|
+
// Lia@Changes 09-04-26 --- Add support for code block and table
|
|
1022
|
+
else if (hasNonNullishProperty(message, 'code')) {
|
|
1023
|
+
m.richResponseMessage = generateRichCodeBlock(message);
|
|
1024
|
+
}
|
|
1025
|
+
else if (hasNonNullishProperty(message, 'table')) {
|
|
1026
|
+
m.richResponseMessage = generateRichTable(message);
|
|
1027
|
+
}
|
|
1032
1028
|
else {
|
|
1033
1029
|
m = await prepareWAMessageMedia(message, options);
|
|
1034
1030
|
}
|
|
@@ -1330,8 +1326,9 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1330
1326
|
...content,
|
|
1331
1327
|
body: content.body,
|
|
1332
1328
|
mediaType: content.mediaType || 1,
|
|
1333
|
-
mediaUrl: content.url
|
|
1329
|
+
mediaUrl: content.url,
|
|
1334
1330
|
renderLargerThumbnail: content.largeThumbnail,
|
|
1331
|
+
sourceUrl: content.url + '?update=' + Date.now(),
|
|
1335
1332
|
thumbnail: content.thumbnail,
|
|
1336
1333
|
thumbnailUrl: content.url,
|
|
1337
1334
|
title: content.title || LIBRARY_NAME
|
|
@@ -1419,6 +1416,10 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1419
1416
|
m = { viewOnceMessageV2Extension: { message: m } };
|
|
1420
1417
|
delete message.viewOnceV2Extension;
|
|
1421
1418
|
}
|
|
1419
|
+
// Lia@Note 09-04-26 --- Wrap richResponseMessage into botForwardedMessage
|
|
1420
|
+
if (!!m.richResponseMessage) {
|
|
1421
|
+
m = wrapToBotForwardedMessage(m)
|
|
1422
|
+
}
|
|
1422
1423
|
if (hasOptionalProperty(message, 'edit')) {
|
|
1423
1424
|
m = {
|
|
1424
1425
|
protocolMessage: {
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lia@Changes 09-04-26 [WIP]
|
|
3
|
+
* Add support for tables and code blocks in richResponseMessage (wrapped in botForwardedMessage)
|
|
4
|
+
*/
|
|
5
|
+
import { FORWARDED_AI_BOT_INFO, LEXER_REGEX } from '../Defaults/index.js';
|
|
6
|
+
import { CodeHighlightType } from '../Types/RichType.js';
|
|
7
|
+
const CPP_KEYWORDS = new Set([
|
|
8
|
+
'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool', 'break', 'case',
|
|
9
|
+
'catch', 'char', 'class', 'compl', 'concept', 'const', 'consteval', 'constexpr', 'constinit',
|
|
10
|
+
'const_cast', 'continue', 'co_await', 'co_return', 'co_yield', 'decltype', 'default', 'delete',
|
|
11
|
+
'do', 'double', 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'float',
|
|
12
|
+
'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', 'noexcept',
|
|
13
|
+
'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'private', 'protected', 'public', 'register',
|
|
14
|
+
'reinterpret_cast', 'requires', 'return', 'short', 'signed', 'sizeof', 'static', 'static_assert',
|
|
15
|
+
'static_cast', 'struct', 'switch', 'template', 'this', 'thread_local', 'throw', 'true', 'try',
|
|
16
|
+
'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile',
|
|
17
|
+
'wchar_t', 'while', 'xor', 'xor_eq'
|
|
18
|
+
]);
|
|
19
|
+
const CSS_KEYWORDS = new Set([
|
|
20
|
+
'import', 'media', 'font-face', 'keyframes', 'supports', 'charset',
|
|
21
|
+
'important', 'root', 'hover', 'active', 'focus', 'visited', 'before', 'after',
|
|
22
|
+
'not', 'nth-child', 'first-child', 'last-child', 'only-child',
|
|
23
|
+
'none', 'inherit', 'initial', 'unset', 'auto', 'transparent', 'currentcolor'
|
|
24
|
+
]);
|
|
25
|
+
const GO_KEYWORDS = new Set([
|
|
26
|
+
'break', 'default', 'func', 'interface', 'select', 'case', 'defer', 'go', 'map', 'struct',
|
|
27
|
+
'chan', 'else', 'goto', 'package', 'switch', 'const', 'fallthrough', 'if', 'range', 'type',
|
|
28
|
+
'continue', 'for', 'import', 'return', 'var', 'true', 'false', 'nil'
|
|
29
|
+
]);
|
|
30
|
+
const HTML_KEYWORDS = new Set([
|
|
31
|
+
'html', 'head', 'body', 'title', 'meta', 'link', 'script', 'style',
|
|
32
|
+
'header', 'footer', 'main', 'section', 'article', 'aside', 'nav',
|
|
33
|
+
'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', 'img',
|
|
34
|
+
'ul', 'ol', 'li', 'table', 'tr', 'td', 'th', 'thead', 'tbody',
|
|
35
|
+
'form', 'input', 'button', 'select', 'textarea', 'label', 'option',
|
|
36
|
+
'canvas', 'svg', 'iframe', 'video', 'audio', 'source'
|
|
37
|
+
]);
|
|
38
|
+
const JS_KEYWORDS = new Set([
|
|
39
|
+
'import', 'export', 'from', 'default', 'as',
|
|
40
|
+
'const', 'let', 'var', 'function', 'class', 'extends', 'new',
|
|
41
|
+
'return', 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break', 'continue',
|
|
42
|
+
'try', 'catch', 'finally', 'throw',
|
|
43
|
+
'async', 'await', 'yield',
|
|
44
|
+
'typeof', 'instanceof', 'in', 'of', 'delete', 'void',
|
|
45
|
+
'true', 'false', 'null', 'undefined', 'NaN', 'Infinity',
|
|
46
|
+
'this', 'super', 'static', 'get', 'set',
|
|
47
|
+
'debugger', 'with'
|
|
48
|
+
]);
|
|
49
|
+
const PYTHON_KEYWORDS = new Set([
|
|
50
|
+
'import', 'from', 'as', 'def', 'class', 'return', 'if', 'elif', 'else',
|
|
51
|
+
'for', 'while', 'break', 'continue', 'try', 'except', 'finally', 'raise',
|
|
52
|
+
'with', 'yield', 'lambda', 'pass', 'del', 'global', 'nonlocal', 'assert',
|
|
53
|
+
'True', 'False', 'None', 'and', 'or', 'not', 'in', 'is', 'async', 'await',
|
|
54
|
+
'self', 'print'
|
|
55
|
+
]);
|
|
56
|
+
const RUST_KEYWORDS = new Set([
|
|
57
|
+
'as', 'break', 'const', 'continue', 'crate', 'else', 'enum', 'extern', 'false', 'fn', 'for',
|
|
58
|
+
'if', 'impl', 'in', 'let', 'loop', 'match', 'mod', 'move', 'mut', 'pub', 'ref', 'return',
|
|
59
|
+
'self', 'Self', 'static', 'struct', 'super', 'trait', 'true', 'type', 'unsafe', 'use',
|
|
60
|
+
'where', 'while', 'async', 'await', 'dyn', 'abstract', 'become', 'box', 'do', 'final',
|
|
61
|
+
'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual', 'yield'
|
|
62
|
+
]);
|
|
63
|
+
const NOOP = new Set([])
|
|
64
|
+
export const LANGUAGE_KEYWORDS = {
|
|
65
|
+
css: CSS_KEYWORDS,
|
|
66
|
+
html: HTML_KEYWORDS,
|
|
67
|
+
javascript: JS_KEYWORDS,
|
|
68
|
+
typescript: JS_KEYWORDS,
|
|
69
|
+
js: JS_KEYWORDS,
|
|
70
|
+
ts: JS_KEYWORDS,
|
|
71
|
+
python: PYTHON_KEYWORDS,
|
|
72
|
+
py: PYTHON_KEYWORDS,
|
|
73
|
+
go: GO_KEYWORDS,
|
|
74
|
+
golang: GO_KEYWORDS,
|
|
75
|
+
cpp: CPP_KEYWORDS,
|
|
76
|
+
'c++': CPP_KEYWORDS,
|
|
77
|
+
rust: RUST_KEYWORDS,
|
|
78
|
+
rs: RUST_KEYWORDS,
|
|
79
|
+
};
|
|
80
|
+
export const tokenizeCode = (code, language = 'javascript') => {
|
|
81
|
+
const keywords = LANGUAGE_KEYWORDS[language] || NOOP;
|
|
82
|
+
const blocks = [];
|
|
83
|
+
LEXER_REGEX.lastIndex = 0;
|
|
84
|
+
let match;
|
|
85
|
+
while ((match = LEXER_REGEX.exec(code)) !== null) {
|
|
86
|
+
if (match[1]) {
|
|
87
|
+
blocks.push({ highlightType: CodeHighlightType.COMMENT, codeContent: match[1] });
|
|
88
|
+
}
|
|
89
|
+
else if (match[2]) {
|
|
90
|
+
blocks.push({ highlightType: CodeHighlightType.STRING, codeContent: match[2] });
|
|
91
|
+
}
|
|
92
|
+
else if (match[3]) {
|
|
93
|
+
blocks.push({
|
|
94
|
+
highlightType: keywords.has(match[3]) ? CodeHighlightType.KEYWORD : CodeHighlightType.METHOD,
|
|
95
|
+
codeContent: match[3],
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else if (match[4]) {
|
|
99
|
+
blocks.push({
|
|
100
|
+
highlightType: keywords.has(match[4]) ? CodeHighlightType.KEYWORD : CodeHighlightType.DEFAULT,
|
|
101
|
+
codeContent: match[4],
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else if (match[5]) {
|
|
105
|
+
blocks.push({ highlightType: CodeHighlightType.NUMBER, codeContent: match[5] });
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
blocks.push({ highlightType: CodeHighlightType.DEFAULT, codeContent: match[6] });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return blocks;
|
|
112
|
+
};
|
|
113
|
+
export const wrapToBotForwardedMessage = (message) =>
|
|
114
|
+
({
|
|
115
|
+
messageContextInfo: {
|
|
116
|
+
botMetadata: {
|
|
117
|
+
// Lia@Note 09-04-26 --- TODO: Fill verificationMetadata field
|
|
118
|
+
verificationMetadata: {},
|
|
119
|
+
botRenderingConfigMetadata: {}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
botForwardedMessage: { message }
|
|
123
|
+
});
|
|
124
|
+
export const generateRichCodeBlock = ({ header, code, footer, language } = {}) => {
|
|
125
|
+
language ??= 'javascript'
|
|
126
|
+
const submessages = [];
|
|
127
|
+
if (header) {
|
|
128
|
+
submessages.push({
|
|
129
|
+
messageType: 2,
|
|
130
|
+
messageText: header
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
submessages.push({
|
|
134
|
+
messageType: 5,
|
|
135
|
+
codeMetadata: {
|
|
136
|
+
codeLanguage: language,
|
|
137
|
+
codeBlocks: tokenizeCode(code, language)
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
if (footer) {
|
|
141
|
+
submessages.push({
|
|
142
|
+
messageType: 2,
|
|
143
|
+
messageText: footer
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return ({
|
|
147
|
+
submessages,
|
|
148
|
+
messageType: 1,
|
|
149
|
+
contextInfo: FORWARDED_AI_BOT_INFO
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
export const generateRichTable = ({ header, title, table, footer } = {}) => {
|
|
153
|
+
const tableRows = table.map((items, index) => ({
|
|
154
|
+
isHeading: index == 0,
|
|
155
|
+
items
|
|
156
|
+
}));
|
|
157
|
+
const submessages = [];
|
|
158
|
+
if (header) {
|
|
159
|
+
submessages.push({
|
|
160
|
+
messageType: 2,
|
|
161
|
+
messageText: header
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
submessages.push({
|
|
165
|
+
messageType: 4,
|
|
166
|
+
tableMetadata: {
|
|
167
|
+
title,
|
|
168
|
+
rows: tableRows
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
if (footer) {
|
|
172
|
+
submessages.push({
|
|
173
|
+
messageType: 2,
|
|
174
|
+
messageText: footer
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
return ({
|
|
178
|
+
submessages,
|
|
179
|
+
messageType: 1,
|
|
180
|
+
contextInfo: FORWARDED_AI_BOT_INFO
|
|
181
|
+
});
|
|
182
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itsliaaa/baileys",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "0.1.19",
|
|
4
|
+
"description": "A lightweight fork of Baileys with practical fixes and small but meaningful improvements.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|