@pontasockets/baileys 0.3.2 → 0.3.4
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/lib/Utils/auth-utils.js
CHANGED
|
@@ -404,7 +404,7 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
|
|
|
404
404
|
const key = key_
|
|
405
405
|
transactionCache[key] = transactionCache[key] || {}
|
|
406
406
|
// Special handling for pre-keys and signed-pre-keys
|
|
407
|
-
if (key === 'pre-key') {
|
|
407
|
+
if (key === 'pre-key' || key === 'signed-pre-key') {
|
|
408
408
|
await handlePreKeyOperations(data, key, transactionCache, mutations, logger, true)
|
|
409
409
|
}
|
|
410
410
|
else {
|
|
@@ -475,17 +475,22 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
|
|
|
475
475
|
if (transactionsInProgress === 1) {
|
|
476
476
|
logger.trace('entering transaction')
|
|
477
477
|
}
|
|
478
|
-
// Release the transaction mutex now that we've updated the counter
|
|
479
|
-
// This allows other transactions to start preparing
|
|
480
|
-
releaseTxMutex()
|
|
481
478
|
try {
|
|
482
479
|
return await executeTransactionWork(work)
|
|
483
480
|
}
|
|
484
481
|
finally {
|
|
485
482
|
cleanupTransactionState();
|
|
483
|
+
// Release AFTER commit & cleanup to prevent race conditions
|
|
484
|
+
// where another transaction starts before this one finishes writing
|
|
485
|
+
releaseTxMutex()
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
catch (error) {
|
|
489
|
+
// Only release here if we haven't already released in the finally block
|
|
490
|
+
// (i.e., error thrown before transactionsInProgress was incremented)
|
|
491
|
+
if (transactionsInProgress > 0) {
|
|
492
|
+
cleanupTransactionState()
|
|
493
|
+
}
|
|
489
494
|
releaseTxMutex()
|
|
490
495
|
throw error
|
|
491
496
|
}
|
|
@@ -520,4 +525,4 @@ module.exports = {
|
|
|
520
525
|
makeCacheableSignalKeyStore,
|
|
521
526
|
addTransactionCapability,
|
|
522
527
|
initAuthCreds
|
|
523
|
-
}
|
|
528
|
+
}
|
|
@@ -40,6 +40,7 @@ const makeEventBuffer = (logger) => {
|
|
|
40
40
|
let data = makeBufferData()
|
|
41
41
|
let isBuffering = false
|
|
42
42
|
let bufferTimeout = null
|
|
43
|
+
let flushPendingTimeout = null
|
|
43
44
|
let bufferCount = 0
|
|
44
45
|
const MAX_HISTORY_CACHE_SIZE = 10000 // Limit the history cache size to prevent memory bloat
|
|
45
46
|
const BUFFER_TIMEOUT_MS = 30000 // 30 seconds
|
|
@@ -81,11 +82,15 @@ const makeEventBuffer = (logger) => {
|
|
|
81
82
|
isBuffering = false
|
|
82
83
|
bufferCount = 0
|
|
83
84
|
|
|
84
|
-
// Clear
|
|
85
|
+
// Clear timeouts
|
|
85
86
|
if (bufferTimeout) {
|
|
86
87
|
clearTimeout(bufferTimeout)
|
|
87
88
|
bufferTimeout = null
|
|
88
89
|
}
|
|
90
|
+
if (flushPendingTimeout) {
|
|
91
|
+
clearTimeout(flushPendingTimeout)
|
|
92
|
+
flushPendingTimeout = null
|
|
93
|
+
}
|
|
89
94
|
|
|
90
95
|
// Clear history cache if it exceeds the max size
|
|
91
96
|
if (historyCache.size > MAX_HISTORY_CACHE_SIZE) {
|
|
@@ -138,15 +143,6 @@ const makeEventBuffer = (logger) => {
|
|
|
138
143
|
buffer()
|
|
139
144
|
try {
|
|
140
145
|
const result = await work(...args)
|
|
141
|
-
|
|
142
|
-
// If this is the only buffer, flush after a small delay
|
|
143
|
-
if (bufferCount === 1) {
|
|
144
|
-
setTimeout(() => {
|
|
145
|
-
if (isBuffering && bufferCount === 1) {
|
|
146
|
-
flush()
|
|
147
|
-
}
|
|
148
|
-
}, 100) // Small delay to allow nested buffers
|
|
149
|
-
}
|
|
150
146
|
return result
|
|
151
147
|
}
|
|
152
148
|
catch (error) {
|
|
@@ -155,9 +151,16 @@ const makeEventBuffer = (logger) => {
|
|
|
155
151
|
finally {
|
|
156
152
|
bufferCount = Math.max(0, bufferCount - 1)
|
|
157
153
|
|
|
158
|
-
if (bufferCount === 0) {
|
|
159
|
-
//
|
|
160
|
-
|
|
154
|
+
if (bufferCount === 0 && isBuffering) {
|
|
155
|
+
// Only schedule ONE flush timer at a time to prevent timer storms
|
|
156
|
+
if (!flushPendingTimeout) {
|
|
157
|
+
flushPendingTimeout = setTimeout(() => {
|
|
158
|
+
flushPendingTimeout = null
|
|
159
|
+
if (isBuffering && bufferCount === 0) {
|
|
160
|
+
flush()
|
|
161
|
+
}
|
|
162
|
+
}, 100)
|
|
163
|
+
}
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
}
|
|
@@ -591,4 +594,4 @@ const stringifyMessageKey = (key) => `${key.remoteJid},${key.id},${key.fromMe ?
|
|
|
591
594
|
|
|
592
595
|
module.exports = {
|
|
593
596
|
makeEventBuffer
|
|
594
|
-
}
|
|
597
|
+
}
|
package/lib/Utils/messages.js
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
"use strict"
|
|
2
2
|
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function(mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : {
|
|
5
|
-
"default": mod
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
3
|
Object.defineProperty(exports, "__esModule", {
|
|
10
4
|
value: true
|
|
11
5
|
})
|
|
12
6
|
|
|
13
7
|
const boom_1 = require("@hapi/boom")
|
|
14
|
-
const axios_1 = __importDefault(require("axios"))
|
|
15
8
|
const crypto_1 = require("crypto")
|
|
16
9
|
const fs_1 = require("fs")
|
|
17
10
|
const WAProto_1 = require("../../WAProto")
|
|
@@ -27,7 +20,7 @@ const MIMETYPE_MAP = {
|
|
|
27
20
|
image: 'image/jpeg',
|
|
28
21
|
video: 'video/mp4',
|
|
29
22
|
document: 'application/pdf',
|
|
30
|
-
audio: 'audio/ogg codecs=opus',
|
|
23
|
+
audio: 'audio/ogg; codecs=opus',
|
|
31
24
|
sticker: 'image/webp',
|
|
32
25
|
'product-catalog-image': 'image/jpeg'
|
|
33
26
|
}
|
|
@@ -168,7 +161,7 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
168
161
|
|
|
169
162
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined'
|
|
170
163
|
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined'
|
|
171
|
-
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true
|
|
164
|
+
const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined'
|
|
172
165
|
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true
|
|
173
166
|
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation
|
|
174
167
|
|
|
@@ -321,7 +314,7 @@ const prepareAlbumMessageContent = async (jid, albums, options) => {
|
|
|
321
314
|
},
|
|
322
315
|
...options
|
|
323
316
|
})
|
|
324
|
-
} else if ('video' in
|
|
317
|
+
} else if ('video' in media) {
|
|
325
318
|
mediaMsg = await generateWAMessage(jid, {
|
|
326
319
|
video: media.video,
|
|
327
320
|
...media,
|
|
@@ -383,9 +376,9 @@ const generateForwardMessageContent = (message, forceForward) => {
|
|
|
383
376
|
content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish())
|
|
384
377
|
|
|
385
378
|
let key = Object.keys(content)[0]
|
|
386
|
-
let score = content[key]
|
|
379
|
+
let score = content?.[key]?.contextInfo?.forwardingScore || 0
|
|
387
380
|
|
|
388
|
-
|
|
381
|
+
score += message.key.fromMe && !forceForward ? 0 : 1
|
|
389
382
|
|
|
390
383
|
if (key === 'conversation') {
|
|
391
384
|
content.extendedTextMessage = {
|
|
@@ -905,7 +898,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
905
898
|
directPath: stickerPackUploadResult.directPath,
|
|
906
899
|
fileLength: stickerPackUpload.fileLength,
|
|
907
900
|
mediaKeyTimestamp: generics_1.unixTimestampSeconds(),
|
|
908
|
-
trayIconFileName: `${stickerPackId}.
|
|
901
|
+
trayIconFileName: `${stickerPackId}.webp`,
|
|
909
902
|
imageDataHash,
|
|
910
903
|
thumbnailDirectPath: coverImage.directPath,
|
|
911
904
|
thumbnailFileSha256: coverImage.fileSha256,
|
|
@@ -1189,7 +1182,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
1189
1182
|
}
|
|
1190
1183
|
}
|
|
1191
1184
|
|
|
1192
|
-
if ('footer' in message &&
|
|
1185
|
+
if ('footer' in message && !!message.footer) {
|
|
1193
1186
|
interactiveMessage.footer = {
|
|
1194
1187
|
text: message.footer
|
|
1195
1188
|
}
|
|
@@ -1398,9 +1391,12 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1398
1391
|
messageSecret: crypto_1.randomBytes(32),
|
|
1399
1392
|
...message.messageContextInfo
|
|
1400
1393
|
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
if (!!options?.ephemeralExpiration && key !== 'protocolMessage' && key !== 'ephemeralMessage' && !WABinary_1.isJidNewsletter(jid)) {
|
|
1401
1397
|
innerMessage[key].contextInfo = {
|
|
1402
1398
|
...(innerMessage[key].contextInfo || {}),
|
|
1403
|
-
expiration: options.ephemeralExpiration
|
|
1399
|
+
expiration: options.ephemeralExpiration
|
|
1404
1400
|
}
|
|
1405
1401
|
}
|
|
1406
1402
|
|
|
@@ -1427,6 +1423,10 @@ const generateWAMessage = async (jid, content, options) => {
|
|
|
1427
1423
|
msgId: options.messageId
|
|
1428
1424
|
})
|
|
1429
1425
|
|
|
1426
|
+
if (jid) {
|
|
1427
|
+
options.jid = jid
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
1430
|
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, {
|
|
1431
1431
|
newsletter: WABinary_1.isJidNewsletter(jid),
|
|
1432
1432
|
...options
|
|
@@ -1436,7 +1436,7 @@ const generateWAMessage = async (jid, content, options) => {
|
|
|
1436
1436
|
const getContentType = (content) => {
|
|
1437
1437
|
if (content) {
|
|
1438
1438
|
const keys = Object.keys(content)
|
|
1439
|
-
const key = keys.find(k => (k === 'conversation' || k.
|
|
1439
|
+
const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage' && k !== 'messageContextInfo')
|
|
1440
1440
|
|
|
1441
1441
|
return key
|
|
1442
1442
|
}
|
|
@@ -1459,7 +1459,7 @@ const normalizeMessageContent = (content) => {
|
|
|
1459
1459
|
return content
|
|
1460
1460
|
|
|
1461
1461
|
function getFutureProofMessage(message) {
|
|
1462
|
-
return ((message === null || message === void 0 ? void 0 : message.editedMessage) || (message === null || message === void 0 ? void 0 : message.statusAddYours) || (message === null || message === void 0 ? void 0 : message.botTaskMessage) || (message === null || message === void 0 ? void 0 : message.eventCoverImage) || (message === null || message === void 0 ? void 0 : message.questionMessage) || (message === null || message === void 0 ? void 0 : message.viewOnceMessage) || (message === null || message === void 0 ? void 0 : message.botInvokeMessage) || (message === null || message === void 0 ? void 0 : message.ephemeralMessage) || (message === null || message === void 0 ? void 0 : message.lottieStickerMessage) || (message === null || message === void 0 ? void 0 : message.groupStatusMessage) || (message === null || message === void 0 ? void 0 : message.limitSharingMessage) || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) || (message === null || message === void 0 ? void 0 : message.botForwardedMessage) || (message === null || message === void 0 ? void 0 : message.statusMentionMessage) || (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2) || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4) || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5) || (message === null || message === void 0 ? void 0 : message.associatedChildMessage) || (message === null || message === void 0 ? void 0 : message.groupMentionedMessage) || (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage) || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension) || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage) || (message === null || message === void 0 ? void 0 : message.pollCreationOptionImageMessage))
|
|
1462
|
+
return ((message === null || message === void 0 ? void 0 : message.editedMessage) || (message === null || message === void 0 ? void 0 : message.statusAddYours) || (message === null || message === void 0 ? void 0 : message.botTaskMessage) || (message === null || message === void 0 ? void 0 : message.eventCoverImage) || (message === null || message === void 0 ? void 0 : message.questionMessage) || (message === null || message === void 0 ? void 0 : message.questionReplyMessage) || (message === null || message === void 0 ? void 0 : message.viewOnceMessage) || (message === null || message === void 0 ? void 0 : message.botInvokeMessage) || (message === null || message === void 0 ? void 0 : message.ephemeralMessage) || (message === null || message === void 0 ? void 0 : message.lottieStickerMessage) || (message === null || message === void 0 ? void 0 : message.groupStatusMessage) || (message === null || message === void 0 ? void 0 : message.limitSharingMessage) || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) || (message === null || message === void 0 ? void 0 : message.botForwardedMessage) || (message === null || message === void 0 ? void 0 : message.statusMentionMessage) || (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2) || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4) || (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5) || (message === null || message === void 0 ? void 0 : message.associatedChildMessage) || (message === null || message === void 0 ? void 0 : message.groupMentionedMessage) || (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage) || (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2Extension) || (message === null || message === void 0 ? void 0 : message.documentWithCaptionMessage) || (message === null || message === void 0 ? void 0 : message.pollCreationOptionImageMessage) || (message === null || message === void 0 ? void 0 : message.spoilerMessage) || (message === null || message === void 0 ? void 0 : message.newsletterAdminProfileMessage) || (message === null || message === void 0 ? void 0 : message.newsletterAdminProfileMessageV2) || (message === null || message === void 0 ? void 0 : message.newsletterAdminProfileStatusMessage))
|
|
1463
1463
|
}
|
|
1464
1464
|
}
|
|
1465
1465
|
|
|
@@ -1617,7 +1617,7 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404]
|
|
|
1617
1617
|
|
|
1618
1618
|
const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
1619
1619
|
const result = await downloadMsg().catch(async (error) => {
|
|
1620
|
-
if (ctx &&
|
|
1620
|
+
if (ctx && typeof error?.status === 'number' && REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
|
|
1621
1621
|
ctx.logger.info({
|
|
1622
1622
|
key: message.key
|
|
1623
1623
|
}, 'sending reupload media request...')
|
|
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true })
|
|
|
8
8
|
|
|
9
9
|
const async_mutex_1 = __importDefault(require("async-mutex"))
|
|
10
10
|
const promises_1 = require("fs/promises")
|
|
11
|
+
const { rename: fsRename } = promises_1
|
|
11
12
|
const path_1 = require("path")
|
|
12
13
|
const WAProto_1 = require("../../WAProto")
|
|
13
14
|
const auth_utils_1 = require("./auth-utils")
|
|
@@ -37,13 +38,20 @@ const getFileLock = (path) => {
|
|
|
37
38
|
* Would recommend writing an auth state for use with a proper SQL or No-SQL DB
|
|
38
39
|
* */
|
|
39
40
|
const useMultiFileAuthState = async (folder) => {
|
|
41
|
+
// Debounce timers per file to avoid rapid successive writes hammering disk
|
|
42
|
+
const writeDebounceTimers = new Map()
|
|
43
|
+
const WRITE_DEBOUNCE_MS = 300
|
|
44
|
+
|
|
40
45
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
46
|
const writeData = async (data, file) => {
|
|
42
47
|
const filePath = path_1.join(folder, fixFileName(file))
|
|
43
48
|
const mutex = getFileLock(filePath)
|
|
44
49
|
return mutex.acquire().then(async (release) => {
|
|
45
50
|
try {
|
|
46
|
-
|
|
51
|
+
// Atomic write: write to temp file then rename to prevent corruption
|
|
52
|
+
const tmpPath = filePath + '.tmp'
|
|
53
|
+
await promises_1.writeFile(tmpPath, JSON.stringify(data, generics_1.BufferJSON.replacer))
|
|
54
|
+
await fsRename(tmpPath, filePath)
|
|
47
55
|
} finally {
|
|
48
56
|
release()
|
|
49
57
|
}
|
|
@@ -120,7 +128,24 @@ const useMultiFileAuthState = async (folder) => {
|
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
130
|
},
|
|
123
|
-
saveCreds
|
|
131
|
+
// saveCreds debounced by default — aman dipanggil tiap creds.update
|
|
132
|
+
// tanpa spam disk. Untuk force immediate write, pakai saveCredsNow.
|
|
133
|
+
saveCreds: () => {
|
|
134
|
+
const existing = writeDebounceTimers.get('creds.json')
|
|
135
|
+
if (existing) clearTimeout(existing)
|
|
136
|
+
const timer = setTimeout(() => {
|
|
137
|
+
writeDebounceTimers.delete('creds.json')
|
|
138
|
+
writeData(creds, 'creds.json').catch(err => {
|
|
139
|
+
console.error('[useMultiFileAuthState] Failed to save creds.json:', err)
|
|
140
|
+
})
|
|
141
|
+
}, WRITE_DEBOUNCE_MS)
|
|
142
|
+
writeDebounceTimers.set('creds.json', timer)
|
|
143
|
+
},
|
|
144
|
+
// Force immediate write — pakai saat disconnect/cleanup agar creds tidak hilang
|
|
145
|
+
saveCredsNow: async () => {
|
|
146
|
+
const existing = writeDebounceTimers.get('creds.json')
|
|
147
|
+
if (existing) clearTimeout(existing)
|
|
148
|
+
writeDebounceTimers.delete('creds.json')
|
|
124
149
|
return writeData(creds, 'creds.json')
|
|
125
150
|
}
|
|
126
151
|
}
|
|
@@ -128,4 +153,4 @@ const useMultiFileAuthState = async (folder) => {
|
|
|
128
153
|
|
|
129
154
|
module.exports = {
|
|
130
155
|
useMultiFileAuthState
|
|
131
|
-
}
|
|
156
|
+
}
|
|
@@ -58,7 +58,7 @@ const generateLoginNode = (userJid, config) => {
|
|
|
58
58
|
const { user, device } = WABinary_1.jidDecode(userJid)
|
|
59
59
|
const payload = {
|
|
60
60
|
...getClientPayload(config),
|
|
61
|
-
passive:
|
|
61
|
+
passive: true,
|
|
62
62
|
pull: true,
|
|
63
63
|
username: +user,
|
|
64
64
|
device: device,
|
|
@@ -185,4 +185,4 @@ module.exports = {
|
|
|
185
185
|
generateRegistrationNode,
|
|
186
186
|
configureSuccessfulPairing,
|
|
187
187
|
encodeSignedDeviceIdentity
|
|
188
|
-
}
|
|
188
|
+
}
|