@itsliaaa/baileys 0.1.17 → 0.1.18
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 +65 -2
- 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/Utils/event-buffer.js +17 -1
- package/lib/Utils/message-retry-manager.js +17 -0
- package/lib/Utils/messages.js +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
A lightweight fork of Baileys with
|
|
5
|
+
A lightweight fork of Baileys with practical fixes and small but meaningful improvements.
|
|
6
|
+
|
|
7
|
+
### ✨ Highlights
|
|
8
|
+
|
|
9
|
+
This fork focuses on clarity and safety:
|
|
10
|
+
|
|
11
|
+
- 🚫 No obfuscation. Easy to read and audit.
|
|
12
|
+
- 🚫 No auto-follow channel (newsletter) behavior.
|
|
6
13
|
|
|
7
14
|
### ⚙️ Changes
|
|
8
15
|
|
|
@@ -10,7 +17,7 @@ A lightweight fork of Baileys with a few fixes and a small adjustment.
|
|
|
10
17
|
- 🖼️ Fixed an issue where media could not be sent to newsletters due to an upstream issue.
|
|
11
18
|
- 📁 Reintroduced [`makeInMemoryStore`](#%EF%B8%8F-implementing-a-data-store) with a minimal ESM adaptation and small adjustments for Baileys v7.
|
|
12
19
|
- 📦 Switched FFmpeg execution from `exec` to `spawn` for safer process handling.
|
|
13
|
-
- 🗃️ Added `@napi-rs/image` as a supported image processing backend in `getImageProcessingLibrary()
|
|
20
|
+
- 🗃️ 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
21
|
|
|
15
22
|
#### 📨 Message Handling & Compatibility
|
|
16
23
|
- 👉🏻 Added support for sending [interactive message](#-sending-interactive-messages) types (button, list, interactive, template, carousel).
|
|
@@ -959,6 +966,62 @@ await sock.requestPairingCode(phoneNumber, customPairingCode)
|
|
|
959
966
|
console.log('🔗 Pairing code', ':', customPairingCode)
|
|
960
967
|
```
|
|
961
968
|
|
|
969
|
+
##### 🖼️ Image Processing
|
|
970
|
+
|
|
971
|
+
> [!NOTE]
|
|
972
|
+
Automatically use available image processing library: `sharp`, `@napi-rs/image`, or `jimp`
|
|
973
|
+
|
|
974
|
+
```javascript
|
|
975
|
+
import { getImageProcessingLibrary } from '@itsliaaa/baileys'
|
|
976
|
+
import { readFile } from 'fs/promises'
|
|
977
|
+
|
|
978
|
+
const lib = await getImageProcessingLibrary()
|
|
979
|
+
|
|
980
|
+
const bufferOrFilePath = './path/to/image.jpg'
|
|
981
|
+
const width = 512
|
|
982
|
+
|
|
983
|
+
let output
|
|
984
|
+
|
|
985
|
+
// --- If sharp installed
|
|
986
|
+
if (lib.sharp?.default) {
|
|
987
|
+
const img = lib.sharp.default(bufferOrFilePath)
|
|
988
|
+
|
|
989
|
+
output = await img.resize(width)
|
|
990
|
+
.jpeg({ quality: 80 })
|
|
991
|
+
.toBuffer()
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// --- If @napi-rs/image installed
|
|
995
|
+
else if (lib.image?.Transformer) {
|
|
996
|
+
// --- Must in buffer format
|
|
997
|
+
const inputBuffer = Buffer.isBuffer(bufferOrFilePath)
|
|
998
|
+
? bufferOrFilePath
|
|
999
|
+
: await readFile(bufferOrFilePath)
|
|
1000
|
+
|
|
1001
|
+
const img = new lib.image.Transformer(inputBuffer)
|
|
1002
|
+
|
|
1003
|
+
output = await img.resize(width, undefined, 0)
|
|
1004
|
+
.jpeg(50)
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// --- If jimp installed
|
|
1008
|
+
else if (lib.jimp?.Jimp) {
|
|
1009
|
+
const img = await lib.jimp.Jimp.read(bufferOrFilePath)
|
|
1010
|
+
|
|
1011
|
+
output = await img
|
|
1012
|
+
.resize({ w: width, mode: lib.jimp.ResizeStrategy.BILINEAR })
|
|
1013
|
+
.getBuffer('image/jpeg', { quality: 50 });
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// --- Fallback
|
|
1017
|
+
else {
|
|
1018
|
+
throw new Error('No image processing available')
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
console.log('✅ Process completed!')
|
|
1022
|
+
console.dir(output, { depth: null })
|
|
1023
|
+
```
|
|
1024
|
+
|
|
962
1025
|
##### 📣 Newsletter Management
|
|
963
1026
|
|
|
964
1027
|
```javascript
|
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,
|
|
@@ -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 = () => {
|
|
@@ -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
|
@@ -1330,8 +1330,9 @@ export const generateWAMessageContent = async (message, options) => {
|
|
|
1330
1330
|
...content,
|
|
1331
1331
|
body: content.body,
|
|
1332
1332
|
mediaType: content.mediaType || 1,
|
|
1333
|
-
mediaUrl: content.url
|
|
1333
|
+
mediaUrl: content.url,
|
|
1334
1334
|
renderLargerThumbnail: content.largeThumbnail,
|
|
1335
|
+
sourceUrl: content.url + '?update=' + Date.now(),
|
|
1335
1336
|
thumbnail: content.thumbnail,
|
|
1336
1337
|
thumbnailUrl: content.url,
|
|
1337
1338
|
title: content.title || LIBRARY_NAME
|
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.18",
|
|
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": {
|