@nexustechpro/baileys 2.1.0 → 2.1.2
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 +1 -1
- package/lib/Defaults/index.js +1 -0
- package/lib/Socket/chats.js +180 -272
- package/lib/Socket/messages-recv.js +4 -2
- package/lib/Socket/messages-send.js +9 -3
- package/lib/Utils/chat-utils.js +319 -620
- package/lib/Utils/messages.js +89 -64
- package/lib/Utils/use-multi-file-auth-state.js +18 -8
- package/lib/index.js +1 -1
- package/package.json +2 -2
package/lib/Utils/messages.js
CHANGED
|
@@ -334,7 +334,10 @@ export const generateWAMessageContent = async (message, options = {}) => {
|
|
|
334
334
|
} else if ('groupInvite' in message) {
|
|
335
335
|
m = await handleGroupInvite(message, options)
|
|
336
336
|
} else if ('stickerPack' in message) {
|
|
337
|
-
|
|
337
|
+
const result = await prepareStickerPackMessage(message.stickerPack, options)
|
|
338
|
+
return result.isBatched
|
|
339
|
+
? { stickerPackMessage: result.stickerPackMessage, isBatched: true, batchCount: result.batchCount }
|
|
340
|
+
: WAProto.Message.create({ stickerPackMessage: result.stickerPackMessage })
|
|
338
341
|
} else if ('pin' in message) {
|
|
339
342
|
const messageKey = typeof message.pin === 'boolean'
|
|
340
343
|
? (options.quoted?.key || (() => { throw new Boom('No quoted message key found for pin operation') })())
|
|
@@ -460,81 +463,99 @@ export const generateWAMessageContent = async (message, options = {}) => {
|
|
|
460
463
|
// ─── STICKER PACK ─────────────────────────────────────────────────────────────
|
|
461
464
|
export const prepareStickerPackMessage = async (stickerPack, options) => {
|
|
462
465
|
const { stickers, cover, name, publisher, packId, description } = stickerPack
|
|
463
|
-
|
|
464
|
-
|
|
466
|
+
const MAX_STICKER_SIZE = 1024 * 1024
|
|
467
|
+
const MAX_STICKERS_PER_PACK = 60
|
|
465
468
|
|
|
469
|
+
if (!stickers?.length) throw new Boom('Sticker pack must contain at least one sticker', { statusCode: 400 })
|
|
470
|
+
|
|
471
|
+
const stickerPackIdValue = packId || generateMessageIDV2()
|
|
466
472
|
const lib = await getImageProcessingLibrary()
|
|
467
|
-
const
|
|
473
|
+
const validStickers = []
|
|
474
|
+
const skippedStickers = []
|
|
468
475
|
|
|
469
476
|
const isWebPBuffer = (buf) => buf.length >= 12 && buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50
|
|
470
|
-
const isAnimatedWebP = (buf) => {
|
|
471
|
-
if (!isWebPBuffer(buf)) return false
|
|
472
|
-
let offset = 12
|
|
473
|
-
while (offset < buf.length - 8) {
|
|
474
|
-
const fourCC = buf.toString('ascii', offset, offset + 4)
|
|
475
|
-
const chunkSize = buf.readUInt32LE(offset + 4)
|
|
476
|
-
if (fourCC === 'VP8X' && offset + 8 < buf.length && (buf[offset + 8] & 0x02)) return true
|
|
477
|
-
if (fourCC === 'ANIM' || fourCC === 'ANMF') return true
|
|
478
|
-
offset += 8 + chunkSize + (chunkSize % 2)
|
|
479
|
-
}
|
|
480
|
-
return false
|
|
481
|
-
}
|
|
482
|
-
const toWebp = async (buffer) => {
|
|
483
|
-
if ('sharp' in lib && lib.sharp) return await lib.sharp.default(buffer).resize(512, 512, { fit: 'inside', withoutEnlargement: true }).webp({ quality: 75, effort: 6 }).toBuffer()
|
|
484
|
-
if ('jimp' in lib && lib.jimp) return await lib.jimp.Jimp.read(buffer).then(img => img.getBuffer('image/webp'))
|
|
485
|
-
throw new Boom('No image processing library available', { statusCode: 500 })
|
|
486
|
-
}
|
|
487
477
|
|
|
488
|
-
const
|
|
489
|
-
await Promise.all(stickers.map(async (s) => {
|
|
478
|
+
const stickerPromises = stickers.map(async (s, i) => {
|
|
490
479
|
try {
|
|
491
480
|
const { stream } = await getStream(s.data || s.sticker)
|
|
492
481
|
const buffer = await toBuffer(stream)
|
|
493
|
-
if (!buffer?.length) return
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
if (webpBuffer
|
|
482
|
+
if (!buffer?.length) { skippedStickers.push({ index: i, reason: 'Empty buffer' }); return null }
|
|
483
|
+
|
|
484
|
+
const isWebP = isWebPBuffer(buffer)
|
|
485
|
+
let webpBuffer
|
|
486
|
+
try {
|
|
487
|
+
if (isWebP) webpBuffer = buffer
|
|
488
|
+
else if ('sharp' in lib && lib.sharp) webpBuffer = await lib.sharp.default(buffer).webp().toBuffer()
|
|
489
|
+
else if ('jimp' in lib && lib.jimp) webpBuffer = await lib.jimp.Jimp.read(buffer).then(img => img.getBuffer('image/webp'))
|
|
490
|
+
else { skippedStickers.push({ index: i, reason: 'No image processing library' }); return null }
|
|
491
|
+
} catch (convertError) {
|
|
492
|
+
if (!isWebP) { skippedStickers.push({ index: i, reason: `Conversion failed: ${convertError.message}` }); return null }
|
|
493
|
+
throw convertError
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (webpBuffer.length > MAX_STICKER_SIZE) {
|
|
497
|
+
options.logger?.warn?.(`Sticker at index ${i} exceeds 1MB, compressing...`)
|
|
498
|
+
try {
|
|
499
|
+
if ('sharp' in lib && lib.sharp) webpBuffer = await lib.sharp.default(buffer).webp({ quality: 70 }).toBuffer()
|
|
500
|
+
if (webpBuffer.length > MAX_STICKER_SIZE && 'sharp' in lib && lib.sharp) webpBuffer = await lib.sharp.default(buffer).webp({ quality: 50 }).toBuffer()
|
|
501
|
+
if (webpBuffer.length > MAX_STICKER_SIZE) { skippedStickers.push({ index: i, reason: 'Still exceeds 1MB after compression' }); return null }
|
|
502
|
+
options.logger?.info?.(`Sticker ${i} compressed successfully`)
|
|
503
|
+
} catch {
|
|
504
|
+
skippedStickers.push({ index: i, reason: 'Compression failed' })
|
|
505
|
+
return null
|
|
506
|
+
}
|
|
499
507
|
}
|
|
508
|
+
|
|
500
509
|
const hash = sha256(webpBuffer).toString('base64').replace(/\//g, '-').replace(/=/g, '')
|
|
501
|
-
|
|
502
|
-
} catch (e) {
|
|
503
|
-
|
|
510
|
+
return { fileName: `${hash}.webp`, webpBuffer, mimetype: 'image/webp', isAnimated: s.isAnimated || false, isLottie: s.isLottie || false, emojis: s.emojis || [], accessibilityLabel: s.accessibilityLabel || '' }
|
|
511
|
+
} catch (e) {
|
|
512
|
+
options.logger?.warn({ err: e }, 'failed processing sticker')
|
|
513
|
+
skippedStickers.push({ index: i, reason: e.message })
|
|
514
|
+
return null
|
|
515
|
+
}
|
|
516
|
+
})
|
|
504
517
|
|
|
518
|
+
validStickers.push(...(await Promise.all(stickerPromises)).filter(Boolean))
|
|
505
519
|
if (!validStickers.length) throw new Boom('No valid stickers could be processed', { statusCode: 400 })
|
|
506
520
|
|
|
507
521
|
const { stream: covStream } = await getStream(cover)
|
|
508
|
-
const coverBuffer = await
|
|
509
|
-
|
|
510
|
-
|
|
522
|
+
const coverBuffer = await toBuffer(covStream)
|
|
523
|
+
let coverWebpBuffer
|
|
524
|
+
if (isWebPBuffer(coverBuffer)) coverWebpBuffer = coverBuffer
|
|
525
|
+
else if ('sharp' in lib && lib.sharp) coverWebpBuffer = await lib.sharp.default(coverBuffer).webp().toBuffer()
|
|
526
|
+
else if ('jimp' in lib && lib.jimp) coverWebpBuffer = await lib.jimp.Jimp.read(coverBuffer).then(img => img.getBuffer('image/webp'))
|
|
527
|
+
else throw new Boom('No image processing library available for cover', { statusCode: 500 })
|
|
528
|
+
|
|
529
|
+
const processBatch = async (batch, batchIdx, totalBatches) => {
|
|
511
530
|
const batchData = {}
|
|
512
|
-
batch.forEach(s => { batchData[s.fileName] = [new Uint8Array(s.
|
|
513
|
-
const trayFile = `${
|
|
514
|
-
batchData[trayFile] = [new Uint8Array(
|
|
515
|
-
|
|
516
|
-
|
|
531
|
+
batch.forEach(s => { batchData[s.fileName] = [new Uint8Array(s.webpBuffer), { level: 0 }] })
|
|
532
|
+
const trayFile = totalBatches > 1 ? `${stickerPackIdValue}_batch${batchIdx}.webp` : `${stickerPackIdValue}.webp`
|
|
533
|
+
batchData[trayFile] = [new Uint8Array(coverWebpBuffer), { level: 0 }]
|
|
534
|
+
|
|
535
|
+
const zipBuf = await new Promise((resolve, reject) => zip(batchData, (err, data) => err ? reject(err) : resolve(Buffer.from(data))))
|
|
536
|
+
|
|
517
537
|
const upload = await encryptedStream(zipBuf, 'sticker-pack', { logger: options.logger, opts: options.options })
|
|
518
|
-
const uploadRes = await options.upload(upload.encFilePath || upload.encBuffer, { fileEncSha256B64: upload.fileEncSha256.toString('base64'), mediaType: 'sticker-pack', timeoutMs: options.mediaUploadTimeoutMs
|
|
519
|
-
await upload.
|
|
538
|
+
const uploadRes = await options.upload(upload.encFilePath || upload.encBuffer, { fileEncSha256B64: upload.fileEncSha256.toString('base64'), mediaType: 'sticker-pack', timeoutMs: options.mediaUploadTimeoutMs })
|
|
539
|
+
if (upload.encFilePath) await fs.unlink(upload.encFilePath).catch(() => { })
|
|
520
540
|
|
|
521
541
|
let thumbRes = null
|
|
522
542
|
try {
|
|
523
543
|
let thumbBuf
|
|
524
|
-
if ('sharp' in lib && lib.sharp) thumbBuf = await lib.sharp.default(coverBuffer).resize(252, 252
|
|
544
|
+
if ('sharp' in lib && lib.sharp) thumbBuf = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer()
|
|
525
545
|
else if ('jimp' in lib && lib.jimp) thumbBuf = await lib.jimp.Jimp.read(coverBuffer).then(img => img.resize({ w: 252, h: 252 }).getBuffer('image/jpeg'))
|
|
526
546
|
if (thumbBuf?.length) {
|
|
527
547
|
const thumbUpload = await encryptedStream(thumbBuf, 'thumbnail-sticker-pack', { logger: options.logger, opts: options.options, mediaKey: upload.mediaKey })
|
|
528
|
-
thumbRes = await options.upload(thumbUpload.encFilePath || thumbUpload.encBuffer, { fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'), mediaType: 'thumbnail-sticker-pack', timeoutMs: options.mediaUploadTimeoutMs
|
|
529
|
-
await thumbUpload.
|
|
548
|
+
thumbRes = await options.upload(thumbUpload.encFilePath || thumbUpload.encBuffer, { fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'), mediaType: 'thumbnail-sticker-pack', timeoutMs: options.mediaUploadTimeoutMs })
|
|
549
|
+
if (thumbUpload.encFilePath) await fs.unlink(thumbUpload.encFilePath).catch(() => { })
|
|
530
550
|
thumbRes._buf = thumbBuf; thumbRes._enc = thumbUpload
|
|
531
551
|
}
|
|
532
552
|
} catch (e) { options.logger?.warn({ err: e }, 'failed generating sticker pack thumbnail') }
|
|
533
553
|
|
|
534
554
|
return {
|
|
535
|
-
name:
|
|
536
|
-
|
|
537
|
-
|
|
555
|
+
name: totalBatches > 1 ? `${name} (${batchIdx + 1}/${totalBatches})` : name,
|
|
556
|
+
publisher, packDescription: description,
|
|
557
|
+
stickerPackId: totalBatches > 1 ? `${stickerPackIdValue}_${batchIdx}` : stickerPackIdValue,
|
|
558
|
+
stickerPackOrigin: proto.Message.StickerPackMessage.StickerPackOrigin.USER_CREATED,
|
|
538
559
|
stickerPackSize: zipBuf.length,
|
|
539
560
|
stickers: batch.map(s => ({ fileName: s.fileName, mimetype: s.mimetype, isAnimated: s.isAnimated, isLottie: s.isLottie, emojis: s.emojis, accessibilityLabel: s.accessibilityLabel })),
|
|
540
561
|
fileSha256: upload.fileSha256, fileEncSha256: upload.fileEncSha256, mediaKey: upload.mediaKey,
|
|
@@ -543,13 +564,14 @@ export const prepareStickerPackMessage = async (stickerPack, options) => {
|
|
|
543
564
|
}
|
|
544
565
|
}
|
|
545
566
|
|
|
546
|
-
if (validStickers.length >
|
|
567
|
+
if (validStickers.length > MAX_STICKERS_PER_PACK) {
|
|
547
568
|
const batches = []
|
|
548
|
-
for (let i = 0; i < validStickers.length; i +=
|
|
549
|
-
const results =
|
|
569
|
+
for (let i = 0; i < validStickers.length; i += MAX_STICKERS_PER_PACK) batches.push(validStickers.slice(i, i + MAX_STICKERS_PER_PACK))
|
|
570
|
+
const results = []
|
|
571
|
+
for (let i = 0; i < batches.length; i++) results.push(await processBatch(batches[i], i, batches.length))
|
|
550
572
|
return { stickerPackMessage: results, isBatched: true, batchCount: batches.length }
|
|
551
573
|
}
|
|
552
|
-
return { stickerPackMessage: await processBatch(validStickers, 0), isBatched: false }
|
|
574
|
+
return { stickerPackMessage: await processBatch(validStickers, 0, 1), isBatched: false }
|
|
553
575
|
}
|
|
554
576
|
|
|
555
577
|
// ─── MESSAGE BUILDERS ─────────────────────────────────────────────────────────
|
|
@@ -562,18 +584,21 @@ export const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
562
584
|
if (quoted && !isJidNewsletter(jid)) {
|
|
563
585
|
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid)
|
|
564
586
|
const normalizedQuoted = normalizeMessageContent(quoted.message)
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
587
|
+
if (!normalizedQuoted) {
|
|
588
|
+
// stub message with no content — skip quoted context
|
|
589
|
+
} else {
|
|
590
|
+
const quotedType = getContentType(normalizedQuoted)
|
|
591
|
+
const quotedMsg = proto.Message.fromObject({ [quotedType]: normalizedQuoted[quotedType] })
|
|
592
|
+
const quotedContent = quotedMsg[quotedType]
|
|
593
|
+
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) delete quotedContent.contextInfo
|
|
594
|
+
const contextInfo = (innerMessage[key]?.contextInfo) || {}
|
|
595
|
+
contextInfo.participant = jidNormalizedUser(participant)
|
|
596
|
+
contextInfo.stanzaId = quoted.key.id
|
|
597
|
+
contextInfo.quotedMessage = quotedMsg
|
|
598
|
+
if (jid !== quoted.key.remoteJid) contextInfo.remoteJid = quoted.key.remoteJid
|
|
599
|
+
if (innerMessage[key]) innerMessage[key].contextInfo = contextInfo
|
|
600
|
+
}
|
|
575
601
|
}
|
|
576
|
-
|
|
577
602
|
if (options?.ephemeralExpiration && key !== 'protocolMessage' && key !== 'ephemeralMessage' && !isJidNewsletter(jid)) {
|
|
578
603
|
innerMessage[key].contextInfo = { ...(innerMessage[key].contextInfo || {}), expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL }
|
|
579
604
|
}
|
|
@@ -680,7 +705,7 @@ export const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
680
705
|
|
|
681
706
|
export const assertMediaContent = (content) => {
|
|
682
707
|
content = extractMessageContent(content)
|
|
683
|
-
const mediaContent = content?.documentMessage || content?.imageMessage || content?.videoMessage || content?.audioMessage || content?.stickerMessage
|
|
708
|
+
const mediaContent = content?.documentMessage || content?.imageMessage || content?.videoMessage || content?.audioMessage || content?.stickerMessage || content?.stickerPackMessage
|
|
684
709
|
if (!mediaContent) throw new Boom('given message is not a media message', { statusCode: 400, data: content })
|
|
685
710
|
return mediaContent
|
|
686
711
|
}
|
|
@@ -65,7 +65,12 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
|
|
|
65
65
|
const checksum = computeChecksum(serialized)
|
|
66
66
|
const payload = JSON.stringify({ data: JSON.parse(serialized), __checksum: checksum })
|
|
67
67
|
await writeFile(tp, payload)
|
|
68
|
-
|
|
68
|
+
try {
|
|
69
|
+
await rename(tp, fp)
|
|
70
|
+
} catch {
|
|
71
|
+
await writeFile(fp, payload)
|
|
72
|
+
await unlink(tp).catch(() => { })
|
|
73
|
+
}
|
|
69
74
|
} finally {
|
|
70
75
|
release()
|
|
71
76
|
releaseFileLock(fp)
|
|
@@ -84,19 +89,24 @@ export const useMultiFileAuthState = async (folder, options = {}) => {
|
|
|
84
89
|
const parsed = JSON.parse(raw)
|
|
85
90
|
if (parsed.__checksum) {
|
|
86
91
|
const expected = computeChecksum(JSON.stringify(parsed.data))
|
|
87
|
-
if (expected !== parsed.__checksum)
|
|
92
|
+
if (expected !== parsed.__checksum) {
|
|
93
|
+
logger?.warn({ file }, 'checksum mismatch — reinitializing file')
|
|
94
|
+
await writeFile(fp, JSON.stringify({ data: parsed.data, __checksum: computeChecksum(JSON.stringify(parsed.data)) })).catch(() => { })
|
|
95
|
+
return JSON.parse(JSON.stringify(parsed.data), BufferJSON.reviver)
|
|
96
|
+
}
|
|
88
97
|
return JSON.parse(JSON.stringify(parsed.data), BufferJSON.reviver)
|
|
89
98
|
}
|
|
90
|
-
// legacy file
|
|
99
|
+
// legacy file — rewrite with checksum
|
|
100
|
+
const reserialized = JSON.stringify(JSON.parse(raw, BufferJSON.reviver), BufferJSON.replacer)
|
|
101
|
+
const checksum = computeChecksum(reserialized)
|
|
102
|
+
await writeFile(fp, JSON.stringify({ data: JSON.parse(reserialized), __checksum: checksum })).catch(() => { })
|
|
91
103
|
return JSON.parse(raw, BufferJSON.reviver)
|
|
92
104
|
} catch (err) {
|
|
93
|
-
logger?.warn({ file, err: err.message }, 'failed to read auth file')
|
|
105
|
+
logger?.warn({ file, err: err.message }, 'failed to read auth file — reinitializing')
|
|
106
|
+
await unlink(fp).catch(() => { })
|
|
94
107
|
return null
|
|
95
108
|
}
|
|
96
|
-
} finally {
|
|
97
|
-
release()
|
|
98
|
-
releaseFileLock(fp)
|
|
99
|
-
}
|
|
109
|
+
} finally { release(); releaseFileLock(fp) }
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
// ─── Remove File ────────────────────────────────────────────────────────────
|
package/lib/index.js
CHANGED
|
@@ -31,7 +31,7 @@ const banner = `
|
|
|
31
31
|
const info = `
|
|
32
32
|
┌───────────────────────────────────────────────────────────────────────┐
|
|
33
33
|
│ 📦 Package: @nexustechpro/baileys │
|
|
34
|
-
│ 🔖 Version: 2.1.
|
|
34
|
+
│ 🔖 Version: 2.1.2 │
|
|
35
35
|
│ ⚡ Status: Production Ready │
|
|
36
36
|
├───────────────────────────────────────────────────────────────────────┤
|
|
37
37
|
│ 🚀 Advanced WhatsApp Web API Client │
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@nexustechpro/baileys",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "2.1.
|
|
5
|
+
"version": "2.1.2",
|
|
6
6
|
"description": "Advanced WhatsApp Web API built on Baileys — interactive messages, buttons, carousels, products, events, payments, polls, albums, sticker packs and more.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"whatsapp",
|
|
@@ -100,8 +100,8 @@
|
|
|
100
100
|
"dependencies": {
|
|
101
101
|
"@adiwajshing/keyed-db": "^0.2.4",
|
|
102
102
|
"@cacheable/node-cache": "^1.4.0",
|
|
103
|
-
"@microlink/mql": "^0.16.1",
|
|
104
103
|
"@hapi/boom": "^9.1.3",
|
|
104
|
+
"@microlink/mql": "^0.16.1",
|
|
105
105
|
"async-mutex": "^0.5.0",
|
|
106
106
|
"axios": "^1.6.0",
|
|
107
107
|
"cache-manager": "latest",
|