@celestial-community/baileys 0.0.1-security → 1.0.0

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.

Potentially problematic release.


This version of @celestial-community/baileys might be problematic. Click here for more details.

Files changed (175) hide show
  1. package/WAProto/index.js +138933 -0
  2. package/engine-requirements.js +10 -0
  3. package/lib/Defaults/baileys-version.json +7 -0
  4. package/lib/Defaults/index.js +157 -0
  5. package/lib/Defaults/phonenumber-mcc.json +223 -0
  6. package/lib/Signal/Group/ciphertext-message.js +15 -0
  7. package/lib/Signal/Group/group-session-builder.js +94 -0
  8. package/lib/Signal/Group/group_cipher.js +118 -0
  9. package/lib/Signal/Group/index.js +138 -0
  10. package/lib/Signal/Group/keyhelper.js +75 -0
  11. package/lib/Signal/Group/queue-job.js +54 -0
  12. package/lib/Signal/Group/sender-chain-key.js +39 -0
  13. package/lib/Signal/Group/sender-key-distribution-message.js +71 -0
  14. package/lib/Signal/Group/sender-key-message.js +76 -0
  15. package/lib/Signal/Group/sender-key-name.js +50 -0
  16. package/lib/Signal/Group/sender-key-record.js +65 -0
  17. package/lib/Signal/Group/sender-key-state.js +114 -0
  18. package/lib/Signal/Group/sender-message-key.js +33 -0
  19. package/lib/Signal/libsignal.js +204 -0
  20. package/lib/Signal/lid-mapping.js +267 -0
  21. package/lib/Socket/Client/abstract-socket-client.js +13 -0
  22. package/lib/Socket/Client/index.js +32 -0
  23. package/lib/Socket/Client/mobile-socket-client.js +82 -0
  24. package/lib/Socket/Client/web-socket-client.js +89 -0
  25. package/lib/Socket/Denzy-ZeroDay.js +805 -0
  26. package/lib/Socket/business.js +279 -0
  27. package/lib/Socket/chats.js +1169 -0
  28. package/lib/Socket/community.d.ts +120 -0
  29. package/lib/Socket/community.js +388 -0
  30. package/lib/Socket/graphql.js +1122 -0
  31. package/lib/Socket/groups.js +345 -0
  32. package/lib/Socket/index.js +22 -0
  33. package/lib/Socket/interop.js +265 -0
  34. package/lib/Socket/lid-mapping.js +111 -0
  35. package/lib/Socket/messages-recv.js +1385 -0
  36. package/lib/Socket/messages-send.js +956 -0
  37. package/lib/Socket/mex.js +69 -0
  38. package/lib/Socket/newsletter.js +424 -0
  39. package/lib/Socket/privacy.js +229 -0
  40. package/lib/Socket/registration.js +190 -0
  41. package/lib/Socket/socket.js +783 -0
  42. package/lib/Socket/username.d.ts +185 -0
  43. package/lib/Socket/username.js +168 -0
  44. package/lib/Socket/usync.js +80 -0
  45. package/lib/Store/index.js +14 -0
  46. package/lib/Store/keyed-db.js +158 -0
  47. package/lib/Store/make-cache-manager-store.js +88 -0
  48. package/lib/Store/make-in-memory-store.js +484 -0
  49. package/lib/Store/make-ordered-dictionary.js +78 -0
  50. package/lib/Store/object-repository.js +27 -0
  51. package/lib/Types/Auth.js +2 -0
  52. package/lib/Types/Call.js +2 -0
  53. package/lib/Types/Chat.js +10 -0
  54. package/lib/Types/Contact.js +2 -0
  55. package/lib/Types/Events.js +2 -0
  56. package/lib/Types/GroupMetadata.js +2 -0
  57. package/lib/Types/Label.js +27 -0
  58. package/lib/Types/LabelAssociation.js +9 -0
  59. package/lib/Types/Message.js +14 -0
  60. package/lib/Types/MexUpdates.js +19 -0
  61. package/lib/Types/Newsletter.js +38 -0
  62. package/lib/Types/Product.js +2 -0
  63. package/lib/Types/RichType.js +30 -0
  64. package/lib/Types/Signal.js +2 -0
  65. package/lib/Types/Socket.js +2 -0
  66. package/lib/Types/State.js +2 -0
  67. package/lib/Types/USync.js +2 -0
  68. package/lib/Types/index.js +58 -0
  69. package/lib/Utils/anti-ban.js +339 -0
  70. package/lib/Utils/anti-delete.d.ts +158 -0
  71. package/lib/Utils/anti-delete.js +293 -0
  72. package/lib/Utils/antiban-presets.js +91 -0
  73. package/lib/Utils/antiban-profiles.js +43 -0
  74. package/lib/Utils/auth-utils.js +210 -0
  75. package/lib/Utils/baileys-event-stream.js +66 -0
  76. package/lib/Utils/browser-utils.js +52 -0
  77. package/lib/Utils/business.js +261 -0
  78. package/lib/Utils/chat-control.d.ts +113 -0
  79. package/lib/Utils/chat-control.js +230 -0
  80. package/lib/Utils/chat-utils.js +922 -0
  81. package/lib/Utils/companion-reg-client-utils.js +37 -0
  82. package/lib/Utils/contact-graph-warmer.js +208 -0
  83. package/lib/Utils/crypto.js +196 -0
  84. package/lib/Utils/decode-wa-message.js +208 -0
  85. package/lib/Utils/delivery-tracker.js +110 -0
  86. package/lib/Utils/device-fingerprint.js +135 -0
  87. package/lib/Utils/event-buffer.js +531 -0
  88. package/lib/Utils/generics.js +571 -0
  89. package/lib/Utils/group-operation-guard.js +147 -0
  90. package/lib/Utils/health-monitor.js +207 -0
  91. package/lib/Utils/history.js +122 -0
  92. package/lib/Utils/human-entropy.js +226 -0
  93. package/lib/Utils/identity-change-handler.js +72 -0
  94. package/lib/Utils/index.js +83 -0
  95. package/lib/Utils/interactive-message.d.ts +139 -0
  96. package/lib/Utils/interactive-message.js +273 -0
  97. package/lib/Utils/legitimacy-signal-injector.js +180 -0
  98. package/lib/Utils/link-preview.js +106 -0
  99. package/lib/Utils/logger.d.ts +13 -0
  100. package/lib/Utils/logger.js +9 -0
  101. package/lib/Utils/lt-hash.js +54 -0
  102. package/lib/Utils/make-mutex.js +41 -0
  103. package/lib/Utils/message-composer.d.ts +106 -0
  104. package/lib/Utils/message-composer.js +721 -0
  105. package/lib/Utils/message-retry-manager.d.ts +88 -0
  106. package/lib/Utils/message-retry-manager.js +160 -0
  107. package/lib/Utils/message-search.d.ts +52 -0
  108. package/lib/Utils/message-search.js +226 -0
  109. package/lib/Utils/messages-media.js +899 -0
  110. package/lib/Utils/messages.js +2698 -0
  111. package/lib/Utils/noise-handler.js +175 -0
  112. package/lib/Utils/offline-node-processor.js +45 -0
  113. package/lib/Utils/pre-key-manager.js +131 -0
  114. package/lib/Utils/presence-choreographer.js +438 -0
  115. package/lib/Utils/process-message.js +423 -0
  116. package/lib/Utils/rate-limiter.js +232 -0
  117. package/lib/Utils/reconnect-throttle.js +157 -0
  118. package/lib/Utils/reply-ratio-guard.js +137 -0
  119. package/lib/Utils/reporting-utils.js +307 -0
  120. package/lib/Utils/retry-reason-tracker.js +140 -0
  121. package/lib/Utils/rich-message-utils.d.ts +48 -0
  122. package/lib/Utils/rich-message-utils.js +400 -0
  123. package/lib/Utils/rich-response-utils.js +461 -0
  124. package/lib/Utils/scheduling.d.ts +135 -0
  125. package/lib/Utils/scheduling.js +246 -0
  126. package/lib/Utils/session-fingerprint.js +226 -0
  127. package/lib/Utils/session-stability.js +224 -0
  128. package/lib/Utils/signal.js +188 -0
  129. package/lib/Utils/stanza-ack.js +38 -0
  130. package/lib/Utils/state-manager.js +91 -0
  131. package/lib/Utils/status-posting.d.ts +81 -0
  132. package/lib/Utils/status-posting.js +187 -0
  133. package/lib/Utils/stealth-connect.js +124 -0
  134. package/lib/Utils/sync-action-utils.js +55 -0
  135. package/lib/Utils/tc-token-utils.js +171 -0
  136. package/lib/Utils/templates.d.ts +54 -0
  137. package/lib/Utils/templates.js +244 -0
  138. package/lib/Utils/timelock-guard.js +162 -0
  139. package/lib/Utils/use-mongo-file-auth-state.d.ts +6 -0
  140. package/lib/Utils/use-mongo-file-auth-state.js +81 -0
  141. package/lib/Utils/use-multi-file-auth-state.js +125 -0
  142. package/lib/Utils/use-single-file-auth-state.d.ts +13 -0
  143. package/lib/Utils/use-single-file-auth-state.js +86 -0
  144. package/lib/Utils/use-sqlite-auth-state.js +187 -0
  145. package/lib/Utils/vCard.d.ts +71 -0
  146. package/lib/Utils/vCard.js +196 -0
  147. package/lib/Utils/validate-connection.js +253 -0
  148. package/lib/Utils/warmup.js +154 -0
  149. package/lib/WABinary/constants.js +1303 -0
  150. package/lib/WABinary/decode.js +270 -0
  151. package/lib/WABinary/encode.js +279 -0
  152. package/lib/WABinary/generic-utils.js +223 -0
  153. package/lib/WABinary/index.js +34 -0
  154. package/lib/WABinary/jid-utils.js +84 -0
  155. package/lib/WABinary/types.js +2 -0
  156. package/lib/WAM/BinaryInfo.js +13 -0
  157. package/lib/WAM/constants.js +15254 -0
  158. package/lib/WAM/encode.js +149 -0
  159. package/lib/WAM/index.js +32 -0
  160. package/lib/WAUSync/Protocols/USyncContactProtocol.js +37 -0
  161. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +71 -0
  162. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +32 -0
  163. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +49 -0
  164. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
  165. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +58 -0
  166. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -0
  167. package/lib/WAUSync/Protocols/index.js +34 -0
  168. package/lib/WAUSync/USyncQuery.js +99 -0
  169. package/lib/WAUSync/USyncUser.js +26 -0
  170. package/lib/WAUSync/USyncUsernameProtocol.d.ts +9 -0
  171. package/lib/WAUSync/USyncUsernameProtocol.js +37 -0
  172. package/lib/WAUSync/index.js +32 -0
  173. package/lib/index.js +59 -0
  174. package/package.json +105 -5
  175. package/README.md +0 -5
@@ -0,0 +1,2698 @@
1
+ 'use strict'
2
+ var __importDefault =
3
+ (this && this.__importDefault) ||
4
+ function (mod) {
5
+ return mod && mod.__esModule ? mod : { default: mod }
6
+ }
7
+ Object.defineProperty(exports, '__esModule', { value: true })
8
+
9
+ const boom_1 = require('@hapi/boom')
10
+ const axios_1 = __importDefault(require('axios'))
11
+ const crypto_1 = require('crypto')
12
+ const fs_1 = require('fs')
13
+ const WAProto_1 = require('../../WAProto')
14
+ const Defaults_1 = require('../Defaults')
15
+ const Types_1 = require('../Types')
16
+ const WABinary_1 = require('../WABinary')
17
+ const crypto_2 = require('./crypto')
18
+ const generics_1 = require('./generics')
19
+ const messages_media_1 = require('./messages-media')
20
+ const Jimp = require('jimp')
21
+ const { zip } = require('fflate')
22
+ const { randomUUID } = require('crypto')
23
+
24
+ const MIMETYPE_MAP = {
25
+ image: 'image/jpeg',
26
+ video: 'video/mp4',
27
+ document: 'application/pdf',
28
+ audio: 'audio/ogg; codecs=opus',
29
+ sticker: 'image/webp',
30
+ 'product-catalog-image': 'image/jpeg'
31
+ }
32
+ const MessageTypeProto = {
33
+ image: Types_1.WAProto.Message.ImageMessage,
34
+ video: Types_1.WAProto.Message.VideoMessage,
35
+ audio: Types_1.WAProto.Message.AudioMessage,
36
+ sticker: Types_1.WAProto.Message.StickerMessage,
37
+ document: Types_1.WAProto.Message.DocumentMessage
38
+ }
39
+ const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType
40
+
41
+ const extractUrlFromText = (text) => {
42
+ var _a
43
+ return (_a = text.match(Defaults_1.URL_REGEX)) === null || _a === void 0 ? void 0 : _a[0]
44
+ }
45
+ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
46
+ const url = extractUrlFromText(text)
47
+ if (!!getUrlInfo && url) {
48
+ try {
49
+ const urlInfo = await getUrlInfo(url)
50
+ return urlInfo
51
+ } catch (error) {
52
+ logger === null || logger === void 0
53
+ ? void 0
54
+ : logger.warn({ trace: error.stack }, 'url generation failed')
55
+ }
56
+ }
57
+ }
58
+ const assertColor = async (color) => {
59
+ let assertedColor
60
+ if (typeof color === 'number') {
61
+ assertedColor = color > 0 ? color : 0xffffffff + Number(color) + 1
62
+ } else {
63
+ let hex = color.trim().replace('#', '')
64
+ if (hex.length <= 6) {
65
+ hex = 'FF' + hex.padStart(6, '0')
66
+ }
67
+ assertedColor = parseInt(hex, 16)
68
+ return assertedColor
69
+ }
70
+ }
71
+
72
+ const prepareWAMessageMedia = async (message, options) => {
73
+ const logger = options.logger
74
+ let mediaType
75
+ for (const key of Defaults_1.MEDIA_KEYS) {
76
+ if (key in message) {
77
+ mediaType = key
78
+ }
79
+ }
80
+ if (!mediaType) {
81
+ throw new boom_1.Boom('Invalid media type', { statusCode: 400 })
82
+ }
83
+ const uploadData = {
84
+ ...message,
85
+ media: message[mediaType]
86
+ }
87
+ delete uploadData[mediaType]
88
+
89
+ const cacheableKey =
90
+ typeof uploadData.media === 'object' &&
91
+ 'url' in uploadData.media &&
92
+ !!uploadData.media.url &&
93
+ !!options.mediaCache &&
94
+ mediaType + ':' + uploadData.media.url.toString()
95
+
96
+ if (mediaType === 'document' && !uploadData.fileName) {
97
+ uploadData.fileName = 'file'
98
+ }
99
+ if (!uploadData.mimetype) {
100
+ uploadData.mimetype = MIMETYPE_MAP[mediaType]
101
+ }
102
+
103
+ if (cacheableKey) {
104
+ const mediaBuff = options.mediaCache.get(cacheableKey)
105
+ if (mediaBuff) {
106
+ logger === null || logger === void 0
107
+ ? void 0
108
+ : logger.debug({ cacheableKey }, 'got media cache hit')
109
+ const obj = Types_1.WAProto.Message.decode(mediaBuff)
110
+ const key = `${mediaType}Message`
111
+ Object.assign(obj[key], { ...uploadData, media: undefined })
112
+ return obj
113
+ }
114
+ }
115
+
116
+ const requiresDurationComputation =
117
+ mediaType === 'audio' && typeof uploadData.seconds === 'undefined'
118
+ const requiresThumbnailComputation =
119
+ (mediaType === 'image' || mediaType === 'video') &&
120
+ typeof uploadData['jpegThumbnail'] === 'undefined'
121
+ const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true
122
+ const requiresAudioBackground =
123
+ options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true
124
+ const requiresOriginalForSomeProcessing =
125
+ requiresDurationComputation || requiresThumbnailComputation
126
+
127
+ const {
128
+ mediaKey,
129
+ encWriteStream,
130
+ bodyPath,
131
+ fileEncSha256,
132
+ fileSha256,
133
+ fileLength,
134
+ didSaveToTmpPath
135
+ } = await (
136
+ options.newsletter ? messages_media_1.prepareStream : messages_media_1.encryptedStream
137
+ )(uploadData.media, options.mediaTypeOverride || mediaType, {
138
+ logger,
139
+ saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
140
+ opts: options.options
141
+ })
142
+
143
+ const fileEncSha256B64 = (
144
+ options.newsletter
145
+ ? fileSha256
146
+ : fileEncSha256 !== null && fileEncSha256 !== void 0
147
+ ? fileEncSha256
148
+ : fileSha256
149
+ ).toString('base64')
150
+
151
+ const [{ mediaUrl, directPath, handle }] = await Promise.all([
152
+ (async () => {
153
+ const result = await options.upload(encWriteStream, {
154
+ fileEncSha256B64,
155
+ mediaType,
156
+ timeoutMs: options.mediaUploadTimeoutMs
157
+ })
158
+ logger === null || logger === void 0
159
+ ? void 0
160
+ : logger.debug({ mediaType, cacheableKey }, 'uploaded media')
161
+ return result
162
+ })(),
163
+ (async () => {
164
+ try {
165
+ if (requiresThumbnailComputation) {
166
+ const { thumbnail, originalImageDimensions } = await (0,
167
+ messages_media_1.generateThumbnail)(bodyPath, mediaType, options)
168
+ uploadData.jpegThumbnail = thumbnail
169
+ if (!uploadData.width && originalImageDimensions) {
170
+ uploadData.width = originalImageDimensions.width
171
+ uploadData.height = originalImageDimensions.height
172
+ logger === null || logger === void 0
173
+ ? void 0
174
+ : logger.debug('set dimensions')
175
+ }
176
+ logger === null || logger === void 0
177
+ ? void 0
178
+ : logger.debug('generated thumbnail')
179
+ }
180
+ if (requiresDurationComputation) {
181
+ uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath)
182
+ logger === null || logger === void 0
183
+ ? void 0
184
+ : logger.debug('computed audio duration')
185
+ }
186
+ if (requiresWaveformProcessing) {
187
+ uploadData.waveform = await (0, messages_media_1.getAudioWaveform)(
188
+ bodyPath,
189
+ logger
190
+ )
191
+ logger === null || logger === void 0
192
+ ? void 0
193
+ : logger.debug('processed waveform')
194
+ }
195
+ if (requiresAudioBackground) {
196
+ uploadData.backgroundArgb = await assertColor(options.backgroundColor)
197
+ logger === null || logger === void 0
198
+ ? void 0
199
+ : logger.debug('computed backgroundColor audio status')
200
+ }
201
+ } catch (error) {
202
+ logger === null || logger === void 0
203
+ ? void 0
204
+ : logger.warn({ trace: error.stack }, 'failed to obtain extra info')
205
+ }
206
+ })()
207
+ ]).finally(async () => {
208
+ if (!Buffer.isBuffer(encWriteStream)) {
209
+ encWriteStream.destroy()
210
+ }
211
+ if (didSaveToTmpPath && bodyPath) {
212
+ try {
213
+ await fs_1.promises.access(bodyPath)
214
+ await fs_1.promises.unlink(bodyPath)
215
+ logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file')
216
+ } catch (error) {
217
+ logger === null || logger === void 0
218
+ ? void 0
219
+ : logger.warn('failed to remove tmp file')
220
+ }
221
+ }
222
+ })
223
+
224
+ const obj = Types_1.WAProto.Message.fromObject({
225
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
226
+ url: handle ? undefined : mediaUrl,
227
+ directPath,
228
+ mediaKey: mediaKey,
229
+ fileEncSha256: fileEncSha256,
230
+ fileSha256,
231
+ fileLength,
232
+ mediaKeyTimestamp: handle ? undefined : (0, generics_1.unixTimestampSeconds)(),
233
+ ...uploadData,
234
+ media: undefined
235
+ })
236
+ })
237
+ if (uploadData.ptv) {
238
+ obj.ptvMessage = obj.videoMessage
239
+ delete obj.videoMessage
240
+ }
241
+ if (cacheableKey) {
242
+ logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache')
243
+ options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish())
244
+ }
245
+ return obj
246
+ }
247
+
248
+ const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
249
+ ephemeralExpiration = ephemeralExpiration || 0
250
+ const content = {
251
+ ephemeralMessage: {
252
+ message: {
253
+ protocolMessage: {
254
+ type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
255
+ ephemeralExpiration
256
+ }
257
+ }
258
+ }
259
+ }
260
+ return Types_1.WAProto.Message.fromObject(content)
261
+ }
262
+
263
+ async function processLocationThumbnail(input, options = {}) {
264
+ const { maxWidth = 300, maxHeight = 300, quality = 80 } = options
265
+ let buffer
266
+ if (
267
+ typeof input === 'string' &&
268
+ (input.startsWith('http://') || input.startsWith('https://'))
269
+ ) {
270
+ const resp = await axios_1.default.get(input, { responseType: 'arraybuffer' })
271
+ buffer = Buffer.from(resp.data)
272
+ } else if (typeof input === 'string') {
273
+ buffer = await fs_1.promises.readFile(input)
274
+ } else if (Buffer.isBuffer(input)) {
275
+ buffer = input
276
+ } else {
277
+ throw new Error('thumbnail must be URL, path or Buffer')
278
+ }
279
+ const image = await Jimp.read(buffer)
280
+ image.scaleToFit(maxWidth, maxHeight)
281
+ return await image.quality(quality).getBufferAsync(Jimp.MIME_JPEG)
282
+ }
283
+
284
+ async function prepareAlbumMessageContent(jid, albums, options) {
285
+ if (!Array.isArray(albums)) {
286
+ throw new Error('albums must be an array containing media objects.')
287
+ }
288
+ if (albums.length === 0) {
289
+ throw new Error('albums cannot be empty. At least one media item is required.')
290
+ }
291
+ const validCount = albums.filter((m) => 'image' in m || 'video' in m).length
292
+ if (validCount === 0) {
293
+ throw new Error("albums contains no valid media. Use 'image' or 'video' keys.")
294
+ }
295
+
296
+ let mediaHandle
297
+ let mediaMsg
298
+ const message = []
299
+ const albumMsg = generateWAMessageFromContent(
300
+ jid,
301
+ {
302
+ albumMessage: {
303
+ expectedImageCount: albums.filter((item) => 'image' in item).length,
304
+ expectedVideoCount: albums.filter((item) => 'video' in item).length
305
+ }
306
+ },
307
+ options
308
+ )
309
+ await options.conn.relayMessage(jid, albumMsg.message, {
310
+ messageId: albumMsg.key.id
311
+ })
312
+
313
+ for (const media of albums) {
314
+ let content = {}
315
+ if ('image' in media) {
316
+ content = { image: media.image }
317
+ } else if ('video' in media) {
318
+ content = { video: media.video }
319
+ } else {
320
+ continue
321
+ }
322
+ mediaMsg = await generateWAMessage(
323
+ jid,
324
+ { ...content, ...media },
325
+ {
326
+ userJid: options.userJid,
327
+ upload: async (encFilePath, opts) => {
328
+ const up = await options.conn.waUploadToServer(encFilePath, {
329
+ ...opts,
330
+ newsletter: (0, WABinary_1.isJidNewsLetter)(jid)
331
+ })
332
+ mediaHandle = up.handle
333
+ return up
334
+ },
335
+ ...options
336
+ }
337
+ )
338
+ if (mediaMsg) {
339
+ mediaMsg.message.messageContextInfo = {
340
+ messageSecret: (0, crypto_1.randomBytes)(32),
341
+ messageAssociation: {
342
+ associationType: WAProto_1.proto.MessageAssociation.AssociationType.MEDIA_ALBUM,
343
+ parentMessageKey: albumMsg.key
344
+ }
345
+ }
346
+ }
347
+ message.push(mediaMsg)
348
+ }
349
+ return message
350
+ }
351
+
352
+ const generateForwardMessageContent = (message, forceForward) => {
353
+ var _a
354
+ let content = message.message
355
+ if (!content) {
356
+ throw new boom_1.Boom('no content in message', { statusCode: 400 })
357
+ }
358
+ content = normalizeMessageContent(content)
359
+ content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish())
360
+ let key = Object.keys(content)[0]
361
+ let score =
362
+ ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) ||
363
+ 0
364
+ score += message.key.fromMe && !forceForward ? 0 : 1
365
+ if (key === 'conversation') {
366
+ content.extendedTextMessage = { text: content[key] }
367
+ delete content.conversation
368
+ key = 'extendedTextMessage'
369
+ }
370
+ if (score > 0) {
371
+ content[key].contextInfo = { forwardingScore: score, isForwarded: true }
372
+ } else {
373
+ content[key].contextInfo = {}
374
+ }
375
+ return content
376
+ }
377
+
378
+ function extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
379
+ if (!extract) return { text, ie: [], inline_entities: [] }
380
+ const createIE = (type, ie) => {
381
+ if (type === 'hyperlink')
382
+ return {
383
+ key: ie.key,
384
+ metadata: {
385
+ display_name: ie.text,
386
+ is_trusted: ie.is_trusted,
387
+ url: ie.url,
388
+ __typename: 'GenAIInlineLinkItem'
389
+ }
390
+ }
391
+ if (type === 'citation')
392
+ return {
393
+ key: ie.key,
394
+ metadata: {
395
+ reference_id: ie.reference_id,
396
+ reference_url: ie.url,
397
+ reference_title: ie.url,
398
+ reference_display_name: ie.url,
399
+ sources: [],
400
+ __typename: 'GenAISearchCitationItem'
401
+ }
402
+ }
403
+ if (type === 'latex')
404
+ return {
405
+ key: ie.key,
406
+ metadata: {
407
+ latex_expression: ie.text,
408
+ latex_image: {
409
+ url: ie.url,
410
+ width: Number(ie.width) || 100,
411
+ height: Number(ie.height) || 100
412
+ },
413
+ font_height: Number(ie.font_height) || 83.333333333333,
414
+ padding: Number(ie.padding) || 15,
415
+ __typename: 'GenAILatexItem'
416
+ }
417
+ }
418
+ }
419
+ let ie = [],
420
+ inline_entities = [],
421
+ result = '',
422
+ last = 0,
423
+ citation_index = 1,
424
+ hyperlink_index = 0,
425
+ latex_index = 0,
426
+ stack = []
427
+ for (let i = 0; i < text.length; i++) {
428
+ if (text[i] === '[' && text[i - 1] !== '\\') {
429
+ stack.push(i)
430
+ } else if (text[i] === ']' && (text[i + 1] === '(' || text[i + 1] === '<')) {
431
+ let start = stack.pop()
432
+ if (start == null) continue
433
+ let open = text[i + 1],
434
+ close = open === '(' ? ')' : '>',
435
+ type = open === '(' ? 'link' : 'latex',
436
+ end = i + 2,
437
+ depth = 1
438
+ while (end < text.length && depth) {
439
+ if (text[end] === open && text[end - 1] !== '\\') depth++
440
+ else if (text[end] === close && text[end - 1] !== '\\') depth--
441
+ end++
442
+ }
443
+ if (depth) continue
444
+ let raw = text.slice(start + 1, i).trim(),
445
+ url = text.slice(i + 2, end - 1).trim(),
446
+ key,
447
+ tag,
448
+ data
449
+ if (type === 'latex') {
450
+ if (!latex) continue
451
+ let [txt = '', width = null, height = null, font_height = null, padding = null] =
452
+ raw.split('|')
453
+ key = `DENJI_LATEX_${latex_index++}`
454
+ tag = `{{${key}}}${txt || 'image'}{{/${key}}}`
455
+ data = {
456
+ type: 'latex',
457
+ ie: { key, text: txt, url, width, height, font_height, padding }
458
+ }
459
+ } else if (raw) {
460
+ if (!hyperlink) continue
461
+ const trusted = !url.startsWith('!')
462
+ if (!trusted) url = url.slice(1)
463
+ key = `DENJI_HYPERLINK_${hyperlink_index++}`
464
+ tag = `{{${key}}}${url}{{/${key}}}`
465
+ data = { type: 'hyperlink', ie: { key, text: raw, url, is_trusted: trusted } }
466
+ } else {
467
+ if (!citation) continue
468
+ key = `DENJI_CITATION_${citation_index - 1}`
469
+ tag = `{{${key}}}${url}{{/${key}}}`
470
+ data = {
471
+ type: 'citation',
472
+ ie: { reference_id: citation_index++, key, text: '', url }
473
+ }
474
+ }
475
+ result += text.slice(last, start) + tag
476
+ last = end
477
+ ie.push(data)
478
+ const entity = createIE(data.type, data.ie)
479
+ if (entity) inline_entities.push(entity)
480
+ i = end - 1
481
+ }
482
+ }
483
+ result += text.slice(last)
484
+ return { text: result, ie, inline_entities }
485
+ }
486
+
487
+ async function waitAllPromises(input) {
488
+ const isPromise = (v) => v && typeof v.then === 'function'
489
+ const isObject = (v) => v && typeof v === 'object'
490
+ const deep = async (v) => {
491
+ if (isPromise(v)) return deep(await v)
492
+ if (Array.isArray(v)) return Promise.all(v.map(deep))
493
+ if (isObject(v)) {
494
+ const entries = await Promise.all(
495
+ Object.entries(v).map(async ([k, val]) => [k, await deep(val)])
496
+ )
497
+ return Object.fromEntries(entries)
498
+ }
499
+ return v
500
+ }
501
+ return deep(await input)
502
+ }
503
+
504
+ function tokenizer(code, lang = 'javascript') {
505
+ const keywordsMap = {
506
+ javascript: new Set([
507
+ 'break',
508
+ 'case',
509
+ 'catch',
510
+ 'continue',
511
+ 'debugger',
512
+ 'delete',
513
+ 'do',
514
+ 'else',
515
+ 'finally',
516
+ 'for',
517
+ 'function',
518
+ 'if',
519
+ 'in',
520
+ 'instanceof',
521
+ 'new',
522
+ 'return',
523
+ 'switch',
524
+ 'this',
525
+ 'throw',
526
+ 'try',
527
+ 'typeof',
528
+ 'var',
529
+ 'void',
530
+ 'while',
531
+ 'with',
532
+ 'true',
533
+ 'false',
534
+ 'null',
535
+ 'undefined',
536
+ 'class',
537
+ 'const',
538
+ 'let',
539
+ 'super',
540
+ 'extends',
541
+ 'export',
542
+ 'import',
543
+ 'yield',
544
+ 'static',
545
+ 'constructor',
546
+ 'async',
547
+ 'await',
548
+ 'get',
549
+ 'set'
550
+ ]),
551
+ typescript: new Set([
552
+ 'abstract',
553
+ 'any',
554
+ 'as',
555
+ 'asserts',
556
+ 'bigint',
557
+ 'boolean',
558
+ 'declare',
559
+ 'enum',
560
+ 'implements',
561
+ 'infer',
562
+ 'interface',
563
+ 'is',
564
+ 'keyof',
565
+ 'module',
566
+ 'namespace',
567
+ 'never',
568
+ 'readonly',
569
+ 'require',
570
+ 'number',
571
+ 'object',
572
+ 'override',
573
+ 'private',
574
+ 'protected',
575
+ 'public',
576
+ 'satisfies',
577
+ 'string',
578
+ 'symbol',
579
+ 'type',
580
+ 'unknown',
581
+ 'using',
582
+ 'from',
583
+ 'break',
584
+ 'case',
585
+ 'catch',
586
+ 'continue',
587
+ 'do',
588
+ 'else',
589
+ 'finally',
590
+ 'for',
591
+ 'function',
592
+ 'if',
593
+ 'new',
594
+ 'return',
595
+ 'switch',
596
+ 'this',
597
+ 'throw',
598
+ 'try',
599
+ 'var',
600
+ 'void',
601
+ 'while',
602
+ 'class',
603
+ 'const',
604
+ 'let',
605
+ 'extends',
606
+ 'import',
607
+ 'export',
608
+ 'async',
609
+ 'await'
610
+ ]),
611
+ python: new Set([
612
+ 'False',
613
+ 'None',
614
+ 'True',
615
+ 'and',
616
+ 'as',
617
+ 'assert',
618
+ 'async',
619
+ 'await',
620
+ 'break',
621
+ 'class',
622
+ 'continue',
623
+ 'def',
624
+ 'del',
625
+ 'elif',
626
+ 'else',
627
+ 'except',
628
+ 'finally',
629
+ 'for',
630
+ 'from',
631
+ 'global',
632
+ 'if',
633
+ 'import',
634
+ 'in',
635
+ 'is',
636
+ 'lambda',
637
+ 'nonlocal',
638
+ 'not',
639
+ 'or',
640
+ 'pass',
641
+ 'raise',
642
+ 'return',
643
+ 'try',
644
+ 'while',
645
+ 'with',
646
+ 'yield'
647
+ ]),
648
+ java: new Set([
649
+ 'abstract',
650
+ 'assert',
651
+ 'boolean',
652
+ 'break',
653
+ 'byte',
654
+ 'case',
655
+ 'catch',
656
+ 'char',
657
+ 'class',
658
+ 'const',
659
+ 'continue',
660
+ 'default',
661
+ 'do',
662
+ 'double',
663
+ 'else',
664
+ 'enum',
665
+ 'extends',
666
+ 'final',
667
+ 'finally',
668
+ 'float',
669
+ 'for',
670
+ 'goto',
671
+ 'if',
672
+ 'implements',
673
+ 'import',
674
+ 'instanceof',
675
+ 'int',
676
+ 'interface',
677
+ 'long',
678
+ 'native',
679
+ 'new',
680
+ 'package',
681
+ 'private',
682
+ 'protected',
683
+ 'public',
684
+ 'return',
685
+ 'short',
686
+ 'static',
687
+ 'strictfp',
688
+ 'super',
689
+ 'switch',
690
+ 'synchronized',
691
+ 'this',
692
+ 'throw',
693
+ 'throws',
694
+ 'transient',
695
+ 'try',
696
+ 'void',
697
+ 'volatile',
698
+ 'while'
699
+ ]),
700
+ golang: new Set([
701
+ 'break',
702
+ 'case',
703
+ 'chan',
704
+ 'const',
705
+ 'continue',
706
+ 'default',
707
+ 'defer',
708
+ 'else',
709
+ 'fallthrough',
710
+ 'for',
711
+ 'func',
712
+ 'go',
713
+ 'goto',
714
+ 'if',
715
+ 'import',
716
+ 'interface',
717
+ 'map',
718
+ 'package',
719
+ 'range',
720
+ 'return',
721
+ 'select',
722
+ 'struct',
723
+ 'switch',
724
+ 'type',
725
+ 'var'
726
+ ]),
727
+ c: new Set([
728
+ 'auto',
729
+ 'break',
730
+ 'case',
731
+ 'char',
732
+ 'const',
733
+ 'continue',
734
+ 'default',
735
+ 'do',
736
+ 'double',
737
+ 'else',
738
+ 'enum',
739
+ 'extern',
740
+ 'float',
741
+ 'for',
742
+ 'goto',
743
+ 'if',
744
+ 'int',
745
+ 'long',
746
+ 'register',
747
+ 'return',
748
+ 'short',
749
+ 'signed',
750
+ 'sizeof',
751
+ 'static',
752
+ 'struct',
753
+ 'switch',
754
+ 'typedef',
755
+ 'union',
756
+ 'unsigned',
757
+ 'void',
758
+ 'volatile',
759
+ 'while'
760
+ ]),
761
+ cpp: new Set([
762
+ 'alignas',
763
+ 'alignof',
764
+ 'and',
765
+ 'auto',
766
+ 'bool',
767
+ 'break',
768
+ 'case',
769
+ 'catch',
770
+ 'class',
771
+ 'const',
772
+ 'constexpr',
773
+ 'continue',
774
+ 'delete',
775
+ 'do',
776
+ 'double',
777
+ 'else',
778
+ 'enum',
779
+ 'explicit',
780
+ 'export',
781
+ 'extern',
782
+ 'false',
783
+ 'float',
784
+ 'for',
785
+ 'friend',
786
+ 'if',
787
+ 'inline',
788
+ 'int',
789
+ 'long',
790
+ 'mutable',
791
+ 'namespace',
792
+ 'new',
793
+ 'noexcept',
794
+ 'nullptr',
795
+ 'operator',
796
+ 'private',
797
+ 'protected',
798
+ 'public',
799
+ 'return',
800
+ 'short',
801
+ 'signed',
802
+ 'sizeof',
803
+ 'static',
804
+ 'struct',
805
+ 'switch',
806
+ 'template',
807
+ 'this',
808
+ 'throw',
809
+ 'true',
810
+ 'try',
811
+ 'typedef',
812
+ 'typename',
813
+ 'union',
814
+ 'unsigned',
815
+ 'using',
816
+ 'virtual',
817
+ 'void',
818
+ 'while'
819
+ ]),
820
+ php: new Set([
821
+ 'abstract',
822
+ 'and',
823
+ 'array',
824
+ 'as',
825
+ 'break',
826
+ 'callable',
827
+ 'case',
828
+ 'catch',
829
+ 'class',
830
+ 'clone',
831
+ 'const',
832
+ 'continue',
833
+ 'declare',
834
+ 'default',
835
+ 'do',
836
+ 'echo',
837
+ 'else',
838
+ 'elseif',
839
+ 'empty',
840
+ 'enddeclare',
841
+ 'endfor',
842
+ 'endforeach',
843
+ 'endif',
844
+ 'endswitch',
845
+ 'endwhile',
846
+ 'extends',
847
+ 'final',
848
+ 'finally',
849
+ 'fn',
850
+ 'for',
851
+ 'foreach',
852
+ 'function',
853
+ 'global',
854
+ 'goto',
855
+ 'if',
856
+ 'implements',
857
+ 'include',
858
+ 'include_once',
859
+ 'instanceof',
860
+ 'interface',
861
+ 'match',
862
+ 'namespace',
863
+ 'new',
864
+ 'null',
865
+ 'or',
866
+ 'private',
867
+ 'protected',
868
+ 'public',
869
+ 'require',
870
+ 'require_once',
871
+ 'return',
872
+ 'static',
873
+ 'switch',
874
+ 'throw',
875
+ 'trait',
876
+ 'try',
877
+ 'use',
878
+ 'var',
879
+ 'while',
880
+ 'yield'
881
+ ]),
882
+ rust: new Set([
883
+ 'as',
884
+ 'break',
885
+ 'const',
886
+ 'continue',
887
+ 'crate',
888
+ 'else',
889
+ 'enum',
890
+ 'extern',
891
+ 'false',
892
+ 'fn',
893
+ 'for',
894
+ 'if',
895
+ 'impl',
896
+ 'in',
897
+ 'let',
898
+ 'loop',
899
+ 'match',
900
+ 'mod',
901
+ 'move',
902
+ 'mut',
903
+ 'pub',
904
+ 'ref',
905
+ 'return',
906
+ 'self',
907
+ 'Self',
908
+ 'static',
909
+ 'struct',
910
+ 'super',
911
+ 'trait',
912
+ 'true',
913
+ 'type',
914
+ 'unsafe',
915
+ 'use',
916
+ 'where',
917
+ 'while'
918
+ ]),
919
+ html: new Set([
920
+ 'html',
921
+ 'head',
922
+ 'body',
923
+ 'div',
924
+ 'span',
925
+ 'p',
926
+ 'a',
927
+ 'img',
928
+ 'video',
929
+ 'audio',
930
+ 'script',
931
+ 'style',
932
+ 'link',
933
+ 'meta',
934
+ 'form',
935
+ 'input',
936
+ 'button',
937
+ 'table',
938
+ 'tr',
939
+ 'td',
940
+ 'th',
941
+ 'ul',
942
+ 'ol',
943
+ 'li',
944
+ 'section',
945
+ 'article',
946
+ 'header',
947
+ 'footer',
948
+ 'nav',
949
+ 'main'
950
+ ]),
951
+ bash: new Set([
952
+ 'if',
953
+ 'then',
954
+ 'else',
955
+ 'elif',
956
+ 'fi',
957
+ 'for',
958
+ 'while',
959
+ 'do',
960
+ 'done',
961
+ 'case',
962
+ 'esac',
963
+ 'function',
964
+ 'in',
965
+ 'select',
966
+ 'until',
967
+ 'break',
968
+ 'continue',
969
+ 'return',
970
+ 'export',
971
+ 'readonly',
972
+ 'local',
973
+ 'declare'
974
+ ]),
975
+ markdown: new Set(['#', '##', '###', '####', '#####', '######'])
976
+ }
977
+ if (!lang || lang === 'txt' || lang === 'text' || lang === 'plaintext') {
978
+ return {
979
+ codeBlock: [{ codeContent: code, highlightType: 0 }],
980
+ unified_codeBlock: [{ content: code, type: 'DEFAULT' }]
981
+ }
982
+ }
983
+ const TYPE_MAP = {
984
+ 0: 'DEFAULT',
985
+ 1: 'KEYWORD',
986
+ 2: 'METHOD',
987
+ 3: 'STR',
988
+ 4: 'NUMBER',
989
+ 5: 'COMMENT'
990
+ }
991
+ const keywords = keywordsMap[lang.toLowerCase()] || new Set()
992
+ const tokens = []
993
+ let i = 0
994
+ const push = (content, type) => {
995
+ if (!content) return
996
+ const last = tokens[tokens.length - 1]
997
+ if (last && last.highlightType === type) last.codeContent += content
998
+ else tokens.push({ codeContent: content, highlightType: type })
999
+ }
1000
+ const isIdentifier = (char) => {
1001
+ switch (lang.toLowerCase()) {
1002
+ case 'css':
1003
+ return /[a-zA-Z0-9_$-]/.test(char)
1004
+ case 'html':
1005
+ return /[a-zA-Z0-9_$:-]/.test(char)
1006
+ default:
1007
+ return /[a-zA-Z0-9_$]/.test(char)
1008
+ }
1009
+ }
1010
+ while (i < code.length) {
1011
+ const c = code[i]
1012
+ if (/\s/.test(c)) {
1013
+ let s = i
1014
+ while (i < code.length && /\s/.test(code[i])) i++
1015
+ push(code.slice(s, i), 0)
1016
+ continue
1017
+ }
1018
+ if (
1019
+ (c === '/' && code[i + 1] === '/') ||
1020
+ (c === '#' && ['python', 'bash'].includes(lang))
1021
+ ) {
1022
+ let s = i
1023
+ while (i < code.length && code[i] !== '\n') i++
1024
+ push(code.slice(s, i), 5)
1025
+ continue
1026
+ }
1027
+ if (c === '"' || c === "'" || c === '`') {
1028
+ let s = i
1029
+ const q = c
1030
+ i++
1031
+ while (i < code.length) {
1032
+ if (code[i] === '\\' && i + 1 < code.length) i += 2
1033
+ else if (code[i] === q) {
1034
+ i++
1035
+ break
1036
+ } else i++
1037
+ }
1038
+ push(code.slice(s, i), 3)
1039
+ continue
1040
+ }
1041
+ if (/[0-9]/.test(c)) {
1042
+ let s = i
1043
+ while (i < code.length && /[0-9._]/.test(code[i])) i++
1044
+ push(code.slice(s, i), 4)
1045
+ continue
1046
+ }
1047
+ if (/[a-zA-Z_$]/.test(c)) {
1048
+ let s = i
1049
+ while (i < code.length && isIdentifier(code[i])) i++
1050
+ const word = code.slice(s, i)
1051
+ let type = 0
1052
+ if (keywords.has(word)) type = 1
1053
+ else if (lang === 'css') {
1054
+ let j = i
1055
+ while (j < code.length && /\s/.test(code[j])) j++
1056
+ if (code[j] === ':') type = 1
1057
+ } else if (lang === 'html') {
1058
+ let p = s - 1
1059
+ while (p >= 0 && /\s/.test(code[p])) p--
1060
+ if (code[p] === '<' || (code[p] === '/' && code[p - 1] === '<')) type = 1
1061
+ }
1062
+ if (type === 0) {
1063
+ let j = i
1064
+ while (j < code.length && /\s/.test(code[j])) j++
1065
+ if (code[j] === '(') type = 2
1066
+ }
1067
+ push(word, type)
1068
+ continue
1069
+ }
1070
+ push(c, 0)
1071
+ i++
1072
+ }
1073
+ return {
1074
+ codeBlock: tokens,
1075
+ unified_codeBlock: tokens.map((t) => ({
1076
+ content: t.codeContent,
1077
+ type: TYPE_MAP[t.highlightType]
1078
+ }))
1079
+ }
1080
+ }
1081
+
1082
+ function toTableMetadata(arr, { hyperlink = true, citation = true, latex = true } = {}) {
1083
+ if (
1084
+ !Array.isArray(arr) ||
1085
+ !arr.every((row) => Array.isArray(row) && row.every((cell) => typeof cell === 'string'))
1086
+ ) {
1087
+ throw new TypeError('Table must be a nested array of strings')
1088
+ }
1089
+ const [header, ...rows] = arr
1090
+ const maxLen = Math.max(header.length, ...rows.map((r) => r.length))
1091
+ const normalize = (r) => [...r, ...Array(maxLen - r.length).fill('')]
1092
+ const unified_rows = [
1093
+ { is_header: true, cells: normalize(header) },
1094
+ ...rows.map((r) => ({ is_header: false, cells: normalize(r) }))
1095
+ ].map((row) => {
1096
+ const markdown_cells = row.cells.map((cell) => {
1097
+ const extracted = extractIE(cell, { hyperlink, citation, latex })
1098
+ return {
1099
+ text: extracted.text,
1100
+ ...(extracted.inline_entities.length
1101
+ ? { inline_entities: extracted.inline_entities }
1102
+ : {})
1103
+ }
1104
+ })
1105
+ return {
1106
+ ...row,
1107
+ ...(markdown_cells.some((c) => c.inline_entities?.length) ? { markdown_cells } : {})
1108
+ }
1109
+ })
1110
+ const rowsMeta = unified_rows.map((r) => ({
1111
+ items: r.cells,
1112
+ ...(r.is_header ? { isHeading: true } : {})
1113
+ }))
1114
+ return { title: '', rows: rowsMeta, unified_rows }
1115
+ }
1116
+
1117
+ function newLayout(name, data, extra = {}) {
1118
+ return {
1119
+ ...extra,
1120
+ view_model: {
1121
+ [Array.isArray(data) ? 'primitives' : 'primitive']: data,
1122
+ __typename: `GenAI${name}LayoutViewModel`
1123
+ }
1124
+ }
1125
+ }
1126
+
1127
+ const generateWAMessageContent = async (message, options) => {
1128
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
1129
+ var _p, _q
1130
+ let m = {}
1131
+
1132
+ if ('text' in message) {
1133
+ const extContent = { text: message.text }
1134
+ let urlInfo = message.linkPreview
1135
+ if (typeof urlInfo === 'undefined') {
1136
+ urlInfo = await generateLinkPreviewIfRequired(
1137
+ message.text,
1138
+ options.getUrlInfo,
1139
+ options.logger
1140
+ )
1141
+ }
1142
+ if (urlInfo) {
1143
+ extContent.matchedText = urlInfo['matched-text']
1144
+ extContent.jpegThumbnail = urlInfo.jpegThumbnail
1145
+ extContent.description = urlInfo.description
1146
+ extContent.title = urlInfo.title
1147
+ extContent.previewType = 0
1148
+ const img = urlInfo.highQualityThumbnail
1149
+ if (img) {
1150
+ extContent.thumbnailDirectPath = img.directPath
1151
+ extContent.mediaKey = img.mediaKey
1152
+ extContent.mediaKeyTimestamp = img.mediaKeyTimestamp
1153
+ extContent.thumbnailWidth = img.width
1154
+ extContent.thumbnailHeight = img.height
1155
+ extContent.thumbnailSha256 = img.fileSha256
1156
+ extContent.thumbnailEncSha256 = img.fileEncSha256
1157
+ }
1158
+ }
1159
+ if (options.backgroundColor) {
1160
+ extContent.backgroundArgb = await assertColor(options.backgroundColor)
1161
+ }
1162
+ if (options.font) {
1163
+ extContent.font = options.font
1164
+ }
1165
+ m.extendedTextMessage = extContent
1166
+ } else if ('contacts' in message) {
1167
+ const contactLen = message.contacts.contacts.length
1168
+ if (!contactLen) {
1169
+ throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 })
1170
+ }
1171
+ if (contactLen === 1) {
1172
+ m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(
1173
+ message.contacts.contacts[0]
1174
+ )
1175
+ } else {
1176
+ m.contactsArrayMessage = Types_1.WAProto.Message.ContactsArrayMessage.fromObject(
1177
+ message.contacts
1178
+ )
1179
+ }
1180
+ } else if ('location' in message) {
1181
+ m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location)
1182
+ } else if ('react' in message) {
1183
+ if (!message.react.senderTimestampMs) {
1184
+ message.react.senderTimestampMs = Date.now()
1185
+ }
1186
+ m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react)
1187
+ } else if ('delete' in message) {
1188
+ m.protocolMessage = {
1189
+ key: message.delete,
1190
+ type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
1191
+ }
1192
+ } else if ('forward' in message) {
1193
+ m = generateForwardMessageContent(message.forward, message.force)
1194
+ } else if ('disappearingMessagesInChat' in message) {
1195
+ const exp =
1196
+ typeof message.disappearingMessagesInChat === 'boolean'
1197
+ ? message.disappearingMessagesInChat
1198
+ ? Defaults_1.WA_DEFAULT_EPHEMERAL
1199
+ : 0
1200
+ : message.disappearingMessagesInChat
1201
+ m = prepareDisappearingMessageSettingContent(exp)
1202
+ } else if ('groupInvite' in message) {
1203
+ m.groupInviteMessage = {}
1204
+ m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode
1205
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration
1206
+ m.groupInviteMessage.caption = message.groupInvite.text
1207
+ m.groupInviteMessage.groupJid = message.groupInvite.jid
1208
+ m.groupInviteMessage.groupName = message.groupInvite.subject
1209
+ if (options.getProfilePicUrl) {
1210
+ const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview')
1211
+ if (pfpUrl) {
1212
+ const resp = await axios_1.default.get(pfpUrl, { responseType: 'arraybuffer' })
1213
+ if (resp.status === 200) {
1214
+ m.groupInviteMessage.jpegThumbnail = resp.data
1215
+ }
1216
+ }
1217
+ }
1218
+ } else if ('pin' in message) {
1219
+ m.pinInChatMessage = {}
1220
+ m.messageContextInfo = {}
1221
+ m.pinInChatMessage.key = message.pin
1222
+ m.pinInChatMessage.type = message.type
1223
+ m.pinInChatMessage.senderTimestampMs = Date.now()
1224
+ m.messageContextInfo.messageAddOnDurationInSecs =
1225
+ message.type === 1 ? message.time || 86400 : 0
1226
+ } else if ('keep' in message) {
1227
+ m.keepInChatMessage = {}
1228
+ m.keepInChatMessage.key = message.keep
1229
+ m.keepInChatMessage.keepType = message.type
1230
+ m.keepInChatMessage.timestampMs = Date.now()
1231
+ } else if ('call' in message) {
1232
+ m = {
1233
+ scheduledCallCreationMessage: {
1234
+ scheduledTimestampMs:
1235
+ (_a = message.call.time) !== null && _a !== void 0 ? _a : Date.now(),
1236
+ callType: (_b = message.call.type) !== null && _b !== void 0 ? _b : 1,
1237
+ title: message.call.title
1238
+ }
1239
+ }
1240
+ } else if ('paymentInvite' in message) {
1241
+ m.paymentInviteMessage = {
1242
+ serviceType: message.paymentInvite.type,
1243
+ expiryTimestamp: message.paymentInvite.expiry
1244
+ }
1245
+ } else if ('buttonReply' in message) {
1246
+ switch (message.type) {
1247
+ case 'template':
1248
+ m.templateButtonReplyMessage = {
1249
+ selectedDisplayText: message.buttonReply.displayText,
1250
+ selectedId: message.buttonReply.id,
1251
+ selectedIndex: message.buttonReply.index
1252
+ }
1253
+ break
1254
+ case 'plain':
1255
+ m.buttonsResponseMessage = {
1256
+ selectedButtonId: message.buttonReply.id,
1257
+ selectedDisplayText: message.buttonReply.displayText,
1258
+ type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
1259
+ }
1260
+ break
1261
+ }
1262
+ } else if ('ptv' in message && message.ptv) {
1263
+ const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options)
1264
+ m.ptvMessage = videoMessage
1265
+ } else if ('product' in message) {
1266
+ const { imageMessage } = await prepareWAMessageMedia(
1267
+ { image: message.product.productImage },
1268
+ options
1269
+ )
1270
+ m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
1271
+ ...message,
1272
+ product: {
1273
+ ...message.product,
1274
+ productImage: imageMessage
1275
+ }
1276
+ })
1277
+ } else if ('order' in message) {
1278
+ m.orderMessage = Types_1.WAProto.Message.OrderMessage.fromObject({
1279
+ orderId: message.order.id,
1280
+ thumbnail: message.order.thumbnail,
1281
+ itemCount: message.order.itemCount,
1282
+ status: message.order.status,
1283
+ surface: message.order.surface,
1284
+ orderTitle: message.order.title,
1285
+ message: message.order.text,
1286
+ sellerJid: message.order.seller,
1287
+ token: message.order.token,
1288
+ totalAmount1000: message.order.amount,
1289
+ totalCurrencyCode: message.order.currency
1290
+ })
1291
+ } else if ('listReply' in message) {
1292
+ m.listResponseMessage = { ...message.listReply }
1293
+ } else if ('poll' in message) {
1294
+ ;(_p = message.poll).selectableCount || (_p.selectableCount = 0)
1295
+ ;(_q = message.poll).toAnnouncementGroup || (_q.toAnnouncementGroup = false)
1296
+ if (!Array.isArray(message.poll.values)) {
1297
+ throw new boom_1.Boom('Invalid poll values', { statusCode: 400 })
1298
+ }
1299
+ if (
1300
+ message.poll.selectableCount < 0 ||
1301
+ message.poll.selectableCount > message.poll.values.length
1302
+ ) {
1303
+ throw new boom_1.Boom(
1304
+ `poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`,
1305
+ { statusCode: 400 }
1306
+ )
1307
+ }
1308
+ m.messageContextInfo = {
1309
+ messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32)
1310
+ }
1311
+ const pollCreationMessage = {
1312
+ name: message.poll.name,
1313
+ selectableOptionsCount: message.poll.selectableCount,
1314
+ options: message.poll.values.map((optionName) => ({ optionName }))
1315
+ }
1316
+ if (message.poll.toAnnouncementGroup) {
1317
+ m.pollCreationMessageV2 = pollCreationMessage
1318
+ } else {
1319
+ if (message.poll.selectableCount === 1) {
1320
+ m.pollCreationMessageV3 = pollCreationMessage
1321
+ } else {
1322
+ m.pollCreationMessage = pollCreationMessage
1323
+ }
1324
+ }
1325
+ } else if ('event' in message) {
1326
+ m.messageContextInfo = {
1327
+ messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32)
1328
+ }
1329
+ m.eventMessage = { ...message.event }
1330
+ } else if ('inviteAdmin' in message) {
1331
+ m.newsletterAdminInviteMessage = {}
1332
+ m.newsletterAdminInviteMessage.inviteExpiration = message.inviteAdmin.inviteExpiration
1333
+ m.newsletterAdminInviteMessage.caption = message.inviteAdmin.text
1334
+ m.newsletterAdminInviteMessage.newsletterJid = message.inviteAdmin.jid
1335
+ m.newsletterAdminInviteMessage.newsletterName = message.inviteAdmin.subject
1336
+ m.newsletterAdminInviteMessage.jpegThumbnail = message.inviteAdmin.thumbnail
1337
+ } else if ('requestPayment' in message) {
1338
+ const sticker = (
1339
+ (_c = message === null || message === void 0 ? void 0 : message.requestPayment) ===
1340
+ null || _c === void 0
1341
+ ? void 0
1342
+ : _c.sticker
1343
+ )
1344
+ ? await prepareWAMessageMedia(
1345
+ {
1346
+ sticker:
1347
+ (_d =
1348
+ message === null || message === void 0
1349
+ ? void 0
1350
+ : message.requestPayment) === null || _d === void 0
1351
+ ? void 0
1352
+ : _d.sticker,
1353
+ ...options
1354
+ },
1355
+ options
1356
+ )
1357
+ : null
1358
+ let notes = {}
1359
+ if (
1360
+ (_e = message === null || message === void 0 ? void 0 : message.requestPayment) ===
1361
+ null || _e === void 0
1362
+ ? void 0
1363
+ : _e.sticker
1364
+ ) {
1365
+ notes = {
1366
+ stickerMessage: {
1367
+ ...(sticker === null || sticker === void 0 ? void 0 : sticker.stickerMessage),
1368
+ contextInfo:
1369
+ (_f =
1370
+ message === null || message === void 0
1371
+ ? void 0
1372
+ : message.requestPayment) === null || _f === void 0
1373
+ ? void 0
1374
+ : _f.contextInfo
1375
+ }
1376
+ }
1377
+ } else if (message.requestPayment.note) {
1378
+ notes = {
1379
+ extendedTextMessage: {
1380
+ text: message.requestPayment.note,
1381
+ contextInfo:
1382
+ (_g =
1383
+ message === null || message === void 0
1384
+ ? void 0
1385
+ : message.requestPayment) === null || _g === void 0
1386
+ ? void 0
1387
+ : _g.contextInfo
1388
+ }
1389
+ }
1390
+ } else {
1391
+ throw new boom_1.Boom('Invalid media type', { statusCode: 400 })
1392
+ }
1393
+ m.requestPaymentMessage = Types_1.WAProto.Message.RequestPaymentMessage.fromObject({
1394
+ expiryTimestamp: message.requestPayment.expiry,
1395
+ amount1000: message.requestPayment.amount,
1396
+ currencyCodeIso4217: message.requestPayment.currency,
1397
+ requestFrom: message.requestPayment.from,
1398
+ noteMessage: { ...notes },
1399
+ background:
1400
+ (_h = message.requestPayment.background) !== null && _h !== void 0 ? _h : null
1401
+ })
1402
+ } else if ('sharePhoneNumber' in message) {
1403
+ m.protocolMessage = {
1404
+ type: WAProto_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
1405
+ }
1406
+ } else if ('requestPhoneNumber' in message) {
1407
+ m.requestPhoneNumberMessage = {}
1408
+ } else if ('album' in message) {
1409
+ const imageMessages = message.album.filter((item) => 'image' in item)
1410
+ const videoMessages = message.album.filter((item) => 'video' in item)
1411
+ m.albumMessage = WAProto_1.proto.Message.AlbumMessage.fromObject({
1412
+ expectedImageCount: imageMessages.length,
1413
+ expectedVideoCount: videoMessages.length
1414
+ })
1415
+ } else if ('groupStatus' in message) {
1416
+ const gs = message.groupStatus
1417
+ if (!gs.message) throw new Error('groupStatus.message is required')
1418
+ const audienceType = gs.audienceType || 0
1419
+ const backgroundColor = gs.backgroundArgb
1420
+ const textColor = gs.textArgb
1421
+ const font = gs.font
1422
+
1423
+ let messageContent = gs.message
1424
+ if (typeof messageContent === 'string') {
1425
+ messageContent = {
1426
+ extendedTextMessage: {
1427
+ text: messageContent,
1428
+ contextInfo: {
1429
+ statusAudienceMetadata: { audienceType }
1430
+ },
1431
+ ...(backgroundColor && { backgroundArgb: backgroundColor }),
1432
+ ...(textColor && { textArgb: textColor }),
1433
+ ...(font && { font: font })
1434
+ }
1435
+ }
1436
+ } else if (messageContent.extendedTextMessage) {
1437
+ if (backgroundColor) messageContent.extendedTextMessage.backgroundArgb = backgroundColor
1438
+ if (textColor) messageContent.extendedTextMessage.textArgb = textColor
1439
+ if (font) messageContent.extendedTextMessage.font = font
1440
+ messageContent.extendedTextMessage.contextInfo = {
1441
+ ...messageContent.extendedTextMessage.contextInfo,
1442
+ statusAudienceMetadata: { audienceType }
1443
+ }
1444
+ } else if (
1445
+ messageContent.imageMessage ||
1446
+ messageContent.videoMessage ||
1447
+ messageContent.audioMessage ||
1448
+ messageContent.documentMessage
1449
+ ) {
1450
+ const key = Object.keys(messageContent)[0]
1451
+ if (!messageContent[key].contextInfo) {
1452
+ messageContent[key].contextInfo = {}
1453
+ }
1454
+ messageContent[key].contextInfo.statusAudienceMetadata = {
1455
+ audienceType: audienceType
1456
+ }
1457
+ }
1458
+ m = { groupStatusMessageV2: { message: messageContent } }
1459
+ } else if ('orderStatus' in message) {
1460
+ const os = message.orderStatus
1461
+ if (!os.image) throw new Error('image is required for orderStatus')
1462
+ let imageInput = os.image
1463
+ if (
1464
+ typeof imageInput === 'string' &&
1465
+ !imageInput.startsWith('http://') &&
1466
+ !imageInput.startsWith('https://')
1467
+ ) {
1468
+ imageInput = await fs_1.promises.readFile(imageInput)
1469
+ }
1470
+ const media = await prepareWAMessageMedia(
1471
+ { image: imageInput },
1472
+ { upload: options.upload, ...options }
1473
+ )
1474
+ m = {
1475
+ viewOnceMessage: {
1476
+ message: {
1477
+ messageContextInfo: {
1478
+ deviceListMetadata: {},
1479
+ deviceListMetadataVersion: 2
1480
+ },
1481
+ interactiveMessage: WAProto_1.proto.Message.InteractiveMessage.create({
1482
+ header: {
1483
+ title: os.title || 'Order Status',
1484
+ hasMediaAttachment: true,
1485
+ ...media
1486
+ },
1487
+ body: {
1488
+ text: os.text || 'Silakan cek status pesanan Anda.'
1489
+ },
1490
+ footer: {
1491
+ text: os.footer || 'Powered by Denji'
1492
+ },
1493
+ nativeFlowMessage: {
1494
+ buttons: [
1495
+ {
1496
+ name: 'order_status',
1497
+ buttonParamsJson: JSON.stringify({
1498
+ reference_id: os.referenceId || 'Denji-001',
1499
+ order: {
1500
+ status: os.status || 'PROCESSING',
1501
+ subtotal: {
1502
+ value: os.subtotalValue || 0,
1503
+ offset: os.subtotalOffset || 100
1504
+ },
1505
+ tax: {
1506
+ value: os.taxValue || 0,
1507
+ offset: os.taxOffset || 100
1508
+ },
1509
+ currency: os.currency || 'IDR'
1510
+ }
1511
+ })
1512
+ }
1513
+ ]
1514
+ }
1515
+ })
1516
+ }
1517
+ }
1518
+ }
1519
+ } else if ('buttonsMessage' in message) {
1520
+ const bm = message.buttonsMessage
1521
+
1522
+ let locationMessage
1523
+
1524
+ if (bm.locationMessage) {
1525
+ const loc = bm.locationMessage
1526
+ const thumbInput = loc.jpegThumbnail || loc.thumbnail
1527
+
1528
+ let thumb
1529
+ if (thumbInput) {
1530
+ thumb = await processLocationThumbnail(thumbInput)
1531
+ }
1532
+
1533
+ locationMessage = WAProto_1.proto.Message.LocationMessage.create({
1534
+ degreesLatitude: loc.degreesLatitude || 0,
1535
+ degreesLongitude: loc.degreesLongitude || 0,
1536
+ name: loc.name || '',
1537
+ address: loc.address || '',
1538
+ jpegThumbnail: thumb
1539
+ })
1540
+ }
1541
+
1542
+ const buttons = (bm.buttons || []).map((btn) =>
1543
+ WAProto_1.proto.Message.ButtonsMessage.Button.create({
1544
+ buttonId: btn.buttonId || '',
1545
+ buttonText: WAProto_1.proto.Message.ButtonsMessage.Button.ButtonText.create({
1546
+ displayText: btn.buttonText?.displayText || ''
1547
+ }),
1548
+ type: btn.type || 1,
1549
+ nativeFlowInfo: btn.nativeFlowInfo
1550
+ ? WAProto_1.proto.Message.ButtonsMessage.Button.NativeFlowInfo.create({
1551
+ name: btn.nativeFlowInfo.name || '',
1552
+ paramsJson: btn.nativeFlowInfo.paramsJson || '',
1553
+ buttonParamsJson:
1554
+ btn.nativeFlowInfo.buttonParamsJson ||
1555
+ btn.nativeFlowInfo.paramsJson ||
1556
+ ''
1557
+ })
1558
+ : undefined
1559
+ })
1560
+ )
1561
+
1562
+ m = {
1563
+ buttonsMessage: WAProto_1.proto.Message.ButtonsMessage.create({
1564
+ locationMessage,
1565
+ contentText: bm.contentText || '',
1566
+ footerText: bm.footerText || '',
1567
+ buttons,
1568
+ headerType: bm.headerType || 6,
1569
+ viewOnce: !!bm.viewOnce
1570
+ })
1571
+ }
1572
+ } else if ('stickerPack' in message) {
1573
+ const {
1574
+ stickers: stickers,
1575
+ cover: cover,
1576
+ name: name,
1577
+ publisher: publisher,
1578
+ packId: packId,
1579
+ description: description
1580
+ } = message.stickerPack
1581
+ const stickerData = {}
1582
+ const stickerPromises = stickers.map(async (s, i) => {
1583
+ let buffer
1584
+ if (
1585
+ typeof s.sticker === 'string' &&
1586
+ (s.sticker.startsWith('http://') || s.sticker.startsWith('https://'))
1587
+ ) {
1588
+ const resp = await axios_1.default.get(s.sticker, { responseType: 'arraybuffer' })
1589
+ buffer = Buffer.from(resp.data)
1590
+ } else if (typeof s.sticker === 'string') {
1591
+ buffer = await fs_1.promises.readFile(s.sticker)
1592
+ } else if (Buffer.isBuffer(s.sticker)) {
1593
+ buffer = s.sticker
1594
+ } else {
1595
+ throw new Error('sticker must be URL, path or Buffer')
1596
+ }
1597
+ const hash = (0, crypto_2.sha256)(buffer).toString('base64url')
1598
+ const fileName = `${i.toString().padStart(2, '0')}_${hash}.webp`
1599
+ stickerData[fileName] = [new Uint8Array(buffer), { level: 0 }]
1600
+ return {
1601
+ fileName: fileName,
1602
+ mimetype: 'image/webp',
1603
+ isAnimated: s.isAnimated || false,
1604
+ isLottie: s.isLottie || false,
1605
+ emojis: s.emojis || [],
1606
+ accessibilityLabel: s.accessibilityLabel || ''
1607
+ }
1608
+ })
1609
+ const stickerMetadata = await Promise.all(stickerPromises)
1610
+
1611
+ const zipBuffer = await new Promise((resolve, reject) => {
1612
+ zip(stickerData, (err, data) => {
1613
+ if (err) reject(err)
1614
+ else resolve(Buffer.from(data))
1615
+ })
1616
+ })
1617
+
1618
+ let coverBuffer
1619
+ if (
1620
+ typeof cover === 'string' &&
1621
+ (cover.startsWith('http://') || cover.startsWith('https://'))
1622
+ ) {
1623
+ const resp = await axios_1.default.get(cover, { responseType: 'arraybuffer' })
1624
+ coverBuffer = Buffer.from(resp.data)
1625
+ } else if (typeof cover === 'string') {
1626
+ coverBuffer = await fs_1.promises.readFile(cover)
1627
+ } else if (Buffer.isBuffer(cover)) {
1628
+ coverBuffer = cover
1629
+ } else {
1630
+ throw new Error('cover must be URL, path or Buffer')
1631
+ }
1632
+
1633
+ const [stickerPackUpload, coverUpload] = await Promise.all([
1634
+ (0, messages_media_1.encryptedStream)(zipBuffer, 'sticker-pack', {
1635
+ logger: options.logger,
1636
+ opts: options.options
1637
+ }),
1638
+ prepareWAMessageMedia(
1639
+ { image: coverBuffer },
1640
+ { ...options, mediaTypeOverride: 'image' }
1641
+ )
1642
+ ])
1643
+
1644
+ const stickerPackUploadResult = await options.upload(stickerPackUpload.encWriteStream, {
1645
+ fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
1646
+ mediaType: 'sticker-pack',
1647
+ timeoutMs: options.mediaUploadTimeoutMs
1648
+ })
1649
+
1650
+ const coverImage = coverUpload.imageMessage
1651
+ const imageDataHash = (0, crypto_2.sha256)(coverBuffer).toString('base64')
1652
+ const stickerPackId = packId || (0, generics_1.generateMessageID)()
1653
+
1654
+ m.stickerPackMessage = {
1655
+ name: name,
1656
+ publisher: publisher,
1657
+ stickerPackId: stickerPackId,
1658
+ packDescription: description,
1659
+ stickerPackOrigin:
1660
+ WAProto_1.proto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
1661
+ stickerPackSize: stickerPackUpload.fileLength,
1662
+ stickers: stickerMetadata,
1663
+ fileSha256: stickerPackUpload.fileSha256,
1664
+ fileEncSha256: stickerPackUpload.fileEncSha256,
1665
+ mediaKey: stickerPackUpload.mediaKey,
1666
+ directPath: stickerPackUploadResult.directPath,
1667
+ fileLength: stickerPackUpload.fileLength,
1668
+ mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
1669
+ trayIconFileName: `${stickerPackId}.png`,
1670
+ imageDataHash: imageDataHash,
1671
+ thumbnailDirectPath: coverImage.directPath,
1672
+ thumbnailFileSha256: coverImage.fileSha256,
1673
+ thumbnailFileEncSha256: coverImage.fileEncSha256,
1674
+ thumbnailHeight: coverImage.height,
1675
+ thumbnailWidth: coverImage.width
1676
+ }
1677
+ } else if ('richMessage' in message) {
1678
+ const rich = message.richMessage
1679
+ const submessages = []
1680
+ const sections = []
1681
+ const richResponseSources = []
1682
+
1683
+ if (rich.text) {
1684
+ let finalText = rich.text
1685
+ finalText = finalText.replace(/\[citation\]\((.+?)\)/g, (match, url) => {
1686
+ return `[](\n${url})`
1687
+ })
1688
+
1689
+ const parsed = typeof finalText === 'string' ? extractIE(finalText) : finalText
1690
+ const text = parsed.text || parsed
1691
+ const inline_entities = parsed.ie
1692
+ ? parsed.ie
1693
+ .map(({ type, ie }) => {
1694
+ if (type === 'hyperlink')
1695
+ return {
1696
+ key: ie.key,
1697
+ metadata: {
1698
+ display_name: ie.text,
1699
+ is_trusted: ie.is_trusted,
1700
+ url: ie.url,
1701
+ __typename: 'GenAIInlineLinkItem'
1702
+ }
1703
+ }
1704
+ if (type === 'citation')
1705
+ return {
1706
+ key: ie.key,
1707
+ metadata: {
1708
+ reference_id: ie.reference_id,
1709
+ reference_url: ie.url,
1710
+ reference_title: ie.url,
1711
+ reference_display_name: ie.url,
1712
+ sources: [],
1713
+ __typename: 'GenAISearchCitationItem'
1714
+ }
1715
+ }
1716
+ if (type === 'latex')
1717
+ return {
1718
+ key: ie.key,
1719
+ metadata: {
1720
+ latex_expression: ie.text || '',
1721
+ latex_image: {
1722
+ url: ie.url,
1723
+ width: Number(ie.width) || 100,
1724
+ height: Number(ie.height) || 100
1725
+ },
1726
+ font_height: Number(ie.font_height) || 83.33,
1727
+ padding: Number(ie.padding) || 15,
1728
+ __typename: 'GenAILatexItem'
1729
+ }
1730
+ }
1731
+ return null
1732
+ })
1733
+ .filter(Boolean)
1734
+ : []
1735
+ submessages.push({ messageType: 2, messageText: text })
1736
+ sections.push(
1737
+ newLayout('Single', {
1738
+ text,
1739
+ ...(inline_entities.length && { inline_entities }),
1740
+ __typename: 'GenAIMarkdownTextUXPrimitive'
1741
+ })
1742
+ )
1743
+ }
1744
+
1745
+ if (rich.code) {
1746
+ const { language, code } = rich.code
1747
+ const tok = tokenizer(code, language)
1748
+ submessages.push({
1749
+ messageType: 5,
1750
+ codeMetadata: { codeLanguage: language, codeBlocks: tok.codeBlock }
1751
+ })
1752
+ sections.push(
1753
+ newLayout('Single', {
1754
+ language,
1755
+ code_blocks: tok.unified_codeBlock,
1756
+ __typename: 'GenAICodeUXPrimitive'
1757
+ })
1758
+ )
1759
+ }
1760
+
1761
+ if (rich.table) {
1762
+ const meta = toTableMetadata(rich.table)
1763
+ submessages.push({
1764
+ messageType: 4,
1765
+ tableMetadata: { title: meta.title, rows: meta.rows }
1766
+ })
1767
+ sections.push(
1768
+ newLayout('Single', { rows: meta.unified_rows, __typename: 'GenATableUXPrimitive' })
1769
+ )
1770
+ }
1771
+
1772
+ if (rich.image) {
1773
+ const url = rich.image
1774
+ submessages.push({
1775
+ messageType: 1,
1776
+ gridImageMetadata: {
1777
+ gridImageUrl: { imagePreviewUrl: url },
1778
+ imageUrls: [
1779
+ {
1780
+ imagePreviewUrl: url,
1781
+ imageHighResUrl: url,
1782
+ sourceUrl:
1783
+ 'https://chat.whatsapp.com/LtkBIm2k8BU0tY9WJOrlUt?s=cl&p=a&mlu=0'
1784
+ }
1785
+ ]
1786
+ }
1787
+ })
1788
+ sections.push(
1789
+ newLayout('Single', {
1790
+ media: { url, mime_type: 'image/jpeg' },
1791
+ imagine_type: 3,
1792
+ status: { status: 'READY' },
1793
+ __typename: 'GenAIImaginePrimitive'
1794
+ })
1795
+ )
1796
+ }
1797
+
1798
+ if (rich.images) {
1799
+ const urls = Array.isArray(rich.images) ? rich.images : [rich.images]
1800
+ const imageUrls = urls.map((url) => ({
1801
+ imagePreviewUrl: url,
1802
+ imageHighResUrl: url,
1803
+ sourceUrl: 'https://chat.whatsapp.com/LtkBIm2k8BU0tY9WJOrlUt?s=cl&p=a&mlu=0'
1804
+ }))
1805
+ submessages.push({
1806
+ messageType: 1,
1807
+ gridImageMetadata: {
1808
+ gridImageUrl: { imagePreviewUrl: imageUrls[0]?.imagePreviewUrl },
1809
+ imageUrls
1810
+ }
1811
+ })
1812
+ imageUrls.forEach(({ imagePreviewUrl }) => {
1813
+ sections.push(
1814
+ newLayout('Single', {
1815
+ media: { url: imagePreviewUrl, mime_type: 'image/jpeg' },
1816
+ imagine_type: 3,
1817
+ status: { status: 'READY' },
1818
+ __typename: 'GenAIImaginePrimitive'
1819
+ })
1820
+ )
1821
+ })
1822
+ }
1823
+
1824
+ if (rich.video) {
1825
+ const url = rich.video
1826
+ sections.push(
1827
+ newLayout('Single', {
1828
+ media: { url, mime_type: 'video/mp4', duration: 10 },
1829
+ imagine_type: 'ANIMATE',
1830
+ status: { status: 'READY' },
1831
+ __typename: 'GenAIImaginePrimitive'
1832
+ })
1833
+ )
1834
+ }
1835
+
1836
+ if (rich.productSingle) {
1837
+ const product = rich.productSingle
1838
+ sections.push({
1839
+ view_model: {
1840
+ primitive: {
1841
+ title: product.title,
1842
+ brand: product.brand,
1843
+ price: product.price,
1844
+ sale_price: product.sale_price,
1845
+ product_url: product.product_url,
1846
+ image: {
1847
+ url: product.image
1848
+ },
1849
+ additional_images: product.additional_images || [
1850
+ { url: product.icon || product.image }
1851
+ ],
1852
+ __typename: 'GenAIProductItemCardPrimitive'
1853
+ },
1854
+ __typename: 'GenAISingleLayoutViewModel'
1855
+ }
1856
+ })
1857
+ }
1858
+
1859
+ if (rich.productMultiple) {
1860
+ const products = rich.productMultiple
1861
+ sections.push({
1862
+ view_model: {
1863
+ primitives: products.map((item) => ({
1864
+ title: item.title,
1865
+ brand: item.brand,
1866
+ price: item.price,
1867
+ sale_price: item.sale_price,
1868
+ product_url: item.product_url,
1869
+ image: {
1870
+ url: item.image
1871
+ },
1872
+ additional_images: item.additional_images || [
1873
+ { url: item.icon || item.image }
1874
+ ],
1875
+ __typename: 'GenAIProductItemCardPrimitive'
1876
+ })),
1877
+ __typename: 'GenAIHScrollLayoutViewModel'
1878
+ }
1879
+ })
1880
+ }
1881
+
1882
+ if (rich.post) {
1883
+ const posts = Array.isArray(rich.post) ? rich.post : [rich.post]
1884
+ sections.push(
1885
+ newLayout(
1886
+ 'HScroll',
1887
+ posts.map((p) => ({
1888
+ post_id: p.post_id || randomUUID(),
1889
+ source_app: p.source_app || 'INSTAGRAM',
1890
+ post_type: p.post_type || 'IMAGE',
1891
+ orientation: p.orientation || 'LANDSCAPE',
1892
+ title: p.title || '',
1893
+ subtitle: p.subtitle || '',
1894
+ username: p.username || '',
1895
+ is_verified: !!p.is_verified,
1896
+ profile_picture_url: p.profile_picture_url || '',
1897
+ thumbnail_url: p.thumbnail_url || '',
1898
+ post_caption: p.post_caption || '',
1899
+ post_url:
1900
+ p.post_url ||
1901
+ 'https://chat.whatsapp.com/LtkBIm2k8BU0tY9WJOrlUt?s=cl&p=a&mlu=0',
1902
+ post_deeplink:
1903
+ p.post_deeplink ||
1904
+ p.post_url ||
1905
+ 'https://chat.whatsapp.com/LtkBIm2k8BU0tY9WJOrlUt?s=cl&p=a&mlu=0',
1906
+ likes_count: p.likes_count || 0,
1907
+ comments_count: p.comments_count || 0,
1908
+ shares_count: p.shares_count || 0,
1909
+ views_count: p.views_count || 0,
1910
+ footer_label: p.footer_label || '',
1911
+ footer_icon: p.footer_icon || '',
1912
+ is_carousel: posts.length > 1,
1913
+ __typename: 'GenAIPostPrimitive'
1914
+ }))
1915
+ )
1916
+ )
1917
+ }
1918
+
1919
+ if (rich.reels) {
1920
+ const items = Array.isArray(rich.reels) ? rich.reels : [rich.reels]
1921
+ const reels = items.map((i) => ({
1922
+ ...i,
1923
+ _avatar: i.profileIconUrl || i.profile_url || '',
1924
+ _thumbnail: i.thumbnailUrl || i.thumbnail || '',
1925
+ _videoUrl: i.videoUrl || i.url || ''
1926
+ }))
1927
+ submessages.push({
1928
+ messageType: 9,
1929
+ contentItemsMetadata: {
1930
+ contentType: 1,
1931
+ itemsMetadata: reels.map((item) => ({
1932
+ reelItem: {
1933
+ title: item.title || '',
1934
+ profileIconUrl: item._avatar,
1935
+ thumbnailUrl: item._thumbnail,
1936
+ videoUrl: item._videoUrl
1937
+ }
1938
+ }))
1939
+ }
1940
+ })
1941
+ reels.forEach((item, idx) =>
1942
+ richResponseSources.push({
1943
+ provider: 'Denji',
1944
+ thumbnailCDNURL: item._thumbnail,
1945
+ sourceProviderURL: item._videoUrl,
1946
+ sourceQuery: '',
1947
+ faviconCDNURL: item._avatar,
1948
+ citationNumber: idx + 1,
1949
+ sourceTitle: item.title || ''
1950
+ })
1951
+ )
1952
+ sections.push(
1953
+ newLayout(
1954
+ 'HScroll',
1955
+ reels.map((item) => ({
1956
+ reels_url: item._videoUrl,
1957
+ thumbnail_url: item._thumbnail,
1958
+ creator: item.title || '',
1959
+ avatar_url: item._avatar,
1960
+ reels_title: item.reels_title || item.title || '',
1961
+ likes_count: item.likes_count || 0,
1962
+ shares_count: item.shares_count || 0,
1963
+ view_count: item.view_count || 0,
1964
+ reel_source: item.reel_source || 'IG',
1965
+ is_verified: !!(item.is_verified || item.verified),
1966
+ __typename: 'GenAIReelPrimitive'
1967
+ }))
1968
+ )
1969
+ )
1970
+ }
1971
+
1972
+ if (rich.sources) {
1973
+ const sourceArr = Array.isArray(rich.sources) ? rich.sources : [rich.sources]
1974
+ const sourceItems = sourceArr.map((s) => {
1975
+ if (typeof s === 'object' && !Array.isArray(s)) return s
1976
+ let iconUrl = s[0]
1977
+ return {
1978
+ source_type: 'THIRD_PARTY',
1979
+ source_display_name: s[2] || '',
1980
+ source_subtitle: 'AI',
1981
+ source_url: s[1] || '',
1982
+ favicon: { url: iconUrl, mime_type: 'image/jpeg', width: 16, height: 16 }
1983
+ }
1984
+ })
1985
+ sections.push(
1986
+ newLayout('Single', {
1987
+ sources: sourceItems,
1988
+ __typename: 'GenAISearchResultPrimitive'
1989
+ })
1990
+ )
1991
+ }
1992
+
1993
+ if (rich.tip)
1994
+ sections.push(
1995
+ newLayout('Single', { text: rich.tip, __typename: 'GenAIMetadataTextPrimitive' })
1996
+ )
1997
+
1998
+ if (rich.suggestions) {
1999
+ const suggest = Array.isArray(rich.suggestions) ? rich.suggestions : [rich.suggestions]
2000
+ sections.push(
2001
+ newLayout(
2002
+ 'ActionRow',
2003
+ suggest.map((text) => ({
2004
+ prompt_text: text,
2005
+ prompt_type: 'SUGGESTED_PROMPT',
2006
+ __typename: 'GenAIFollowUpSuggestionPillPrimitive'
2007
+ }))
2008
+ )
2009
+ )
2010
+ }
2011
+
2012
+ if (rich.footer)
2013
+ sections.push(
2014
+ newLayout('Single', { text: rich.footer, __typename: 'GenAIMetadataTextPrimitive' })
2015
+ )
2016
+
2017
+ const unifiedData = {
2018
+ response_id: randomUUID(),
2019
+ sections: await waitAllPromises(sections)
2020
+ }
2021
+
2022
+ m = {
2023
+ messageContextInfo: {
2024
+ deviceListMetadata: {},
2025
+ deviceListMetadataVersion: 2,
2026
+ botMetadata: {
2027
+ messageDisclaimerText: rich.title || '',
2028
+ richResponseSourcesMetadata: { sources: richResponseSources }
2029
+ }
2030
+ },
2031
+ botForwardedMessage: {
2032
+ message: {
2033
+ richResponseMessage: {
2034
+ messageType: 1,
2035
+ submessages: await waitAllPromises(submessages),
2036
+ unifiedResponse: {
2037
+ data: Buffer.from(JSON.stringify(unifiedData)).toString('base64')
2038
+ },
2039
+ contextInfo: {
2040
+ forwardingScore: 1,
2041
+ isForwarded: true,
2042
+ forwardedAiBotMessageInfo: { botJid: '0@bot' },
2043
+ forwardOrigin: 4
2044
+ }
2045
+ }
2046
+ }
2047
+ }
2048
+ }
2049
+ } else {
2050
+ m = await prepareWAMessageMedia(message, options)
2051
+ }
2052
+
2053
+ if ('buttons' in message && !!message.buttons) {
2054
+ const buttonsMessage = {
2055
+ buttons: message.buttons.map((b) => ({
2056
+ ...b,
2057
+ type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE
2058
+ }))
2059
+ }
2060
+ if ('text' in message) {
2061
+ buttonsMessage.contentText = message.text
2062
+ buttonsMessage.headerType = ButtonType.EMPTY
2063
+ } else {
2064
+ if ('caption' in message) {
2065
+ buttonsMessage.contentText = message.caption
2066
+ }
2067
+ const type = Object.keys(m)[0].replace('Message', '').toUpperCase()
2068
+ buttonsMessage.headerType = ButtonType[type]
2069
+ Object.assign(buttonsMessage, m)
2070
+ }
2071
+ if ('title' in message && !!message.title) {
2072
+ buttonsMessage.text = message.title
2073
+ buttonsMessage.headerType = ButtonType.TEXT
2074
+ }
2075
+ if ('footer' in message && !!message.footer) {
2076
+ buttonsMessage.footerText = message.footer
2077
+ }
2078
+ if ('contextInfo' in message && !!message.contextInfo) {
2079
+ buttonsMessage.contextInfo = message.contextInfo
2080
+ }
2081
+ if ('mentions' in message && !!message.mentions) {
2082
+ buttonsMessage.contextInfo = { mentionedJid: message.mentions }
2083
+ }
2084
+ m = { buttonsMessage }
2085
+ } else if ('templateButtons' in message && !!message.templateButtons) {
2086
+ const msg = {
2087
+ hydratedButtons: message.hasOwnProperty('templateButtons')
2088
+ ? message.templateButtons
2089
+ : message.templateButtons
2090
+ }
2091
+ if ('text' in message) {
2092
+ msg.hydratedContentText = message.text
2093
+ } else {
2094
+ if ('caption' in message) {
2095
+ msg.hydratedContentText = message.caption
2096
+ }
2097
+ Object.assign(msg, m)
2098
+ }
2099
+ if ('footer' in message && !!message.footer) {
2100
+ msg.hydratedFooterText = message.footer
2101
+ }
2102
+ m = {
2103
+ templateMessage: {
2104
+ fourRowTemplate: msg,
2105
+ hydratedTemplate: msg
2106
+ }
2107
+ }
2108
+ }
2109
+ if ('sections' in message && !!message.sections) {
2110
+ const listMessage = {
2111
+ sections: message.sections,
2112
+ buttonText: message.buttonText,
2113
+ title: message.title,
2114
+ footerText: message.footer,
2115
+ description: message.text,
2116
+ listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
2117
+ }
2118
+ m = { listMessage }
2119
+ }
2120
+ if ('interactiveButtons' in message && !!message.interactiveButtons) {
2121
+ const interactiveMessage = {
2122
+ nativeFlowMessage:
2123
+ Types_1.WAProto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
2124
+ buttons: message.interactiveButtons
2125
+ })
2126
+ }
2127
+ if ('text' in message) {
2128
+ interactiveMessage.body = {
2129
+ text: message.text
2130
+ }
2131
+ } else if ('caption' in message) {
2132
+ interactiveMessage.body = {
2133
+ text: message.caption
2134
+ }
2135
+ interactiveMessage.header = {
2136
+ title: message.title,
2137
+ subtitle: message.subtitle,
2138
+ hasMediaAttachment:
2139
+ (_j = message === null || message === void 0 ? void 0 : message.media) !==
2140
+ null && _j !== void 0
2141
+ ? _j
2142
+ : false
2143
+ }
2144
+ Object.assign(interactiveMessage.header, m)
2145
+ }
2146
+ if ('footer' in message && !!message.footer) {
2147
+ interactiveMessage.footer = {
2148
+ text: message.footer
2149
+ }
2150
+ }
2151
+ if ('title' in message && !!message.title) {
2152
+ interactiveMessage.header = {
2153
+ title: message.title,
2154
+ subtitle: message.subtitle,
2155
+ hasMediaAttachment:
2156
+ (_k = message === null || message === void 0 ? void 0 : message.media) !==
2157
+ null && _k !== void 0
2158
+ ? _k
2159
+ : false
2160
+ }
2161
+ Object.assign(interactiveMessage.header, m)
2162
+ }
2163
+ if ('contextInfo' in message && !!message.contextInfo) {
2164
+ interactiveMessage.contextInfo = message.contextInfo
2165
+ }
2166
+ if ('mentions' in message && !!message.mentions) {
2167
+ interactiveMessage.contextInfo = { mentionedJid: message.mentions }
2168
+ }
2169
+ m = { interactiveMessage }
2170
+ }
2171
+ if ('shop' in message && !!message.shop) {
2172
+ const interactiveMessage = {
2173
+ shopStorefrontMessage:
2174
+ Types_1.WAProto.Message.InteractiveMessage.ShopMessage.fromObject({
2175
+ surface: message.shop,
2176
+ id: message.id
2177
+ })
2178
+ }
2179
+ if ('text' in message) {
2180
+ interactiveMessage.body = {
2181
+ text: message.text
2182
+ }
2183
+ } else if ('caption' in message) {
2184
+ interactiveMessage.body = {
2185
+ text: message.caption
2186
+ }
2187
+ interactiveMessage.header = {
2188
+ title: message.title,
2189
+ subtitle: message.subtitle,
2190
+ hasMediaAttachment:
2191
+ (_l = message === null || message === void 0 ? void 0 : message.media) !==
2192
+ null && _l !== void 0
2193
+ ? _l
2194
+ : false
2195
+ }
2196
+ Object.assign(interactiveMessage.header, m)
2197
+ }
2198
+ if ('footer' in message && !!message.footer) {
2199
+ interactiveMessage.footer = {
2200
+ text: message.footer
2201
+ }
2202
+ }
2203
+ if ('title' in message && !!message.title) {
2204
+ interactiveMessage.header = {
2205
+ title: message.title,
2206
+ subtitle: message.subtitle,
2207
+ hasMediaAttachment:
2208
+ (_m = message === null || message === void 0 ? void 0 : message.media) !==
2209
+ null && _m !== void 0
2210
+ ? _m
2211
+ : false
2212
+ }
2213
+ Object.assign(interactiveMessage.header, m)
2214
+ }
2215
+ if ('contextInfo' in message && !!message.contextInfo) {
2216
+ interactiveMessage.contextInfo = message.contextInfo
2217
+ }
2218
+ if ('mentions' in message && !!message.mentions) {
2219
+ interactiveMessage.contextInfo = { mentionedJid: message.mentions }
2220
+ }
2221
+ m = { interactiveMessage }
2222
+ }
2223
+ if ('viewOnce' in message && !!message.viewOnce) {
2224
+ m = { viewOnceMessage: { message: m } }
2225
+ }
2226
+ if (
2227
+ 'mentions' in message &&
2228
+ ((_o = message.mentions) === null || _o === void 0 ? void 0 : _o.length)
2229
+ ) {
2230
+ const [messageType] = Object.keys(m)
2231
+ m[messageType].contextInfo = m[messageType] || {}
2232
+ m[messageType].contextInfo.mentionedJid = message.mentions
2233
+ }
2234
+ if ('edit' in message) {
2235
+ m = {
2236
+ protocolMessage: {
2237
+ key: message.edit,
2238
+ editedMessage: m,
2239
+ timestampMs: Date.now(),
2240
+ type: Types_1.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
2241
+ }
2242
+ }
2243
+ }
2244
+ if ('contextInfo' in message && !!message.contextInfo) {
2245
+ const [messageType] = Object.keys(m)
2246
+ m[messageType] = m[messageType] || {}
2247
+ m[messageType].contextInfo = message.contextInfo
2248
+ }
2249
+ return Types_1.WAProto.Message.fromObject(m)
2250
+ }
2251
+
2252
+ const generateWAMessageFromContent = (jid, message, options) => {
2253
+ if (!options.timestamp) {
2254
+ options.timestamp = new Date()
2255
+ }
2256
+ const innerMessage = normalizeMessageContent(message)
2257
+ const key = getContentType(innerMessage)
2258
+ const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp)
2259
+ const { quoted, userJid } = options
2260
+
2261
+ if (quoted && !(0, WABinary_1.isJidNewsLetter)(jid)) {
2262
+ const participant = quoted.key.fromMe
2263
+ ? userJid
2264
+ : quoted.participant || quoted.key.participant || quoted.key.remoteJid
2265
+ let quotedMsg = normalizeMessageContent(quoted.message)
2266
+ const msgType = getContentType(quotedMsg)
2267
+ if (quotedMsg) {
2268
+ quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] })
2269
+ const quotedContent = quotedMsg[msgType]
2270
+ if (
2271
+ typeof quotedContent === 'object' &&
2272
+ quotedContent &&
2273
+ 'contextInfo' in quotedContent
2274
+ ) {
2275
+ delete quotedContent.contextInfo
2276
+ }
2277
+ const contextInfo = innerMessage[key].contextInfo || {}
2278
+ contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant)
2279
+ contextInfo.stanzaId = quoted.key.id
2280
+ contextInfo.quotedMessage = quotedMsg
2281
+ if (jid !== quoted.key.remoteJid) {
2282
+ contextInfo.remoteJid = quoted.key.remoteJid
2283
+ }
2284
+ innerMessage[key].contextInfo = contextInfo
2285
+ }
2286
+ }
2287
+
2288
+ if (
2289
+ !!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
2290
+ key !== 'protocolMessage' &&
2291
+ key !== 'ephemeralMessage' &&
2292
+ !(0, WABinary_1.isJidNewsLetter)(jid)
2293
+ ) {
2294
+ innerMessage[key].contextInfo = {
2295
+ ...(innerMessage[key].contextInfo || {}),
2296
+ expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL
2297
+ }
2298
+ }
2299
+
2300
+ message = Types_1.WAProto.Message.fromObject(message)
2301
+ const messageJSON = {
2302
+ key: {
2303
+ remoteJid: jid,
2304
+ fromMe: true,
2305
+ id:
2306
+ (options === null || options === void 0 ? void 0 : options.messageId) ||
2307
+ (0, generics_1.generateMessageIDV2)()
2308
+ },
2309
+ message: message,
2310
+ messageTimestamp: timestamp,
2311
+ messageStubParameters: [],
2312
+ participant:
2313
+ (0, WABinary_1.isJidGroup)(jid) || (0, WABinary_1.isJidStatusBroadcast)(jid)
2314
+ ? userJid
2315
+ : undefined,
2316
+ status: Types_1.WAMessageStatus.PENDING
2317
+ }
2318
+ return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON)
2319
+ }
2320
+
2321
+ const generateWAMessage = async (jid, content, options) => {
2322
+ var _a
2323
+ options.logger =
2324
+ (_a = options === null || options === void 0 ? void 0 : options.logger) === null ||
2325
+ _a === void 0
2326
+ ? void 0
2327
+ : _a.child({ msgId: options.messageId })
2328
+ return generateWAMessageFromContent(
2329
+ jid,
2330
+ await generateWAMessageContent(content, {
2331
+ newsletter: (0, WABinary_1.isJidNewsLetter)(jid),
2332
+ ...options
2333
+ }),
2334
+ options
2335
+ )
2336
+ }
2337
+
2338
+ const getContentType = (content) => {
2339
+ if (content) {
2340
+ const keys = Object.keys(content)
2341
+ const key = keys.find(
2342
+ (k) =>
2343
+ (k === 'conversation' || k.includes('Message')) &&
2344
+ k !== 'senderKeyDistributionMessage'
2345
+ )
2346
+ return key
2347
+ }
2348
+ }
2349
+
2350
+ const normalizeMessageContent = (content) => {
2351
+ if (!content) {
2352
+ return undefined
2353
+ }
2354
+ for (let i = 0; i < 5; i++) {
2355
+ const inner = getFutureProofMessage(content)
2356
+ if (!inner) {
2357
+ break
2358
+ }
2359
+ content = inner.message
2360
+ }
2361
+ return content
2362
+ function getFutureProofMessage(message) {
2363
+ return (
2364
+ (message === null || message === void 0 ? void 0 : message.ephemeralMessage) ||
2365
+ (message === null || message === void 0 ? void 0 : message.viewOnceMessage) ||
2366
+ (message === null || message === void 0
2367
+ ? void 0
2368
+ : message.documentWithCaptionMessage) ||
2369
+ (message === null || message === void 0 ? void 0 : message.viewOnceMessageV2) ||
2370
+ (message === null || message === void 0
2371
+ ? void 0
2372
+ : message.viewOnceMessageV2Extension) ||
2373
+ (message === null || message === void 0 ? void 0 : message.editedMessage) ||
2374
+ (message === null || message === void 0 ? void 0 : message.groupMentionedMessage) ||
2375
+ (message === null || message === void 0 ? void 0 : message.botInvokeMessage) ||
2376
+ (message === null || message === void 0 ? void 0 : message.lottieStickerMessage) ||
2377
+ (message === null || message === void 0 ? void 0 : message.eventCoverImage) ||
2378
+ (message === null || message === void 0 ? void 0 : message.statusMentionMessage) ||
2379
+ (message === null || message === void 0
2380
+ ? void 0
2381
+ : message.pollCreationOptionImageMessage) ||
2382
+ (message === null || message === void 0 ? void 0 : message.associatedChildMessage) ||
2383
+ (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage) ||
2384
+ (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4) ||
2385
+ (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5) ||
2386
+ (message === null || message === void 0 ? void 0 : message.statusAddYours) ||
2387
+ (message === null || message === void 0 ? void 0 : message.groupStatusMessage) ||
2388
+ (message === null || message === void 0 ? void 0 : message.limitSharingMessage) ||
2389
+ (message === null || message === void 0 ? void 0 : message.botTaskMessage) ||
2390
+ (message === null || message === void 0 ? void 0 : message.questionMessage) ||
2391
+ (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2) ||
2392
+ (message === null || message === void 0 ? void 0 : message.botForwardedMessage)
2393
+ )
2394
+ }
2395
+ }
2396
+
2397
+ const extractMessageContent = (content) => {
2398
+ var _a, _b, _c, _d, _e, _f
2399
+ const extractFromTemplateMessage = (msg) => {
2400
+ if (msg.imageMessage) {
2401
+ return { imageMessage: msg.imageMessage }
2402
+ } else if (msg.documentMessage) {
2403
+ return { documentMessage: msg.documentMessage }
2404
+ } else if (msg.videoMessage) {
2405
+ return { videoMessage: msg.videoMessage }
2406
+ } else if (msg.locationMessage) {
2407
+ return { locationMessage: msg.locationMessage }
2408
+ } else {
2409
+ return {
2410
+ conversation:
2411
+ 'contentText' in msg
2412
+ ? msg.contentText
2413
+ : 'hydratedContentText' in msg
2414
+ ? msg.hydratedContentText
2415
+ : ''
2416
+ }
2417
+ }
2418
+ }
2419
+ content = normalizeMessageContent(content)
2420
+ if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
2421
+ return extractFromTemplateMessage(content.buttonsMessage)
2422
+ }
2423
+ if (
2424
+ (_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null ||
2425
+ _a === void 0
2426
+ ? void 0
2427
+ : _a.hydratedFourRowTemplate
2428
+ ) {
2429
+ return extractFromTemplateMessage(
2430
+ (_b = content === null || content === void 0 ? void 0 : content.templateMessage) ===
2431
+ null || _b === void 0
2432
+ ? void 0
2433
+ : _b.hydratedFourRowTemplate
2434
+ )
2435
+ }
2436
+ if (
2437
+ (_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null ||
2438
+ _c === void 0
2439
+ ? void 0
2440
+ : _c.hydratedTemplate
2441
+ ) {
2442
+ return extractFromTemplateMessage(
2443
+ (_d = content === null || content === void 0 ? void 0 : content.templateMessage) ===
2444
+ null || _d === void 0
2445
+ ? void 0
2446
+ : _d.hydratedTemplate
2447
+ )
2448
+ }
2449
+ if (
2450
+ (_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null ||
2451
+ _e === void 0
2452
+ ? void 0
2453
+ : _e.fourRowTemplate
2454
+ ) {
2455
+ return extractFromTemplateMessage(
2456
+ (_f = content === null || content === void 0 ? void 0 : content.templateMessage) ===
2457
+ null || _f === void 0
2458
+ ? void 0
2459
+ : _f.fourRowTemplate
2460
+ )
2461
+ }
2462
+ return content
2463
+ }
2464
+
2465
+ const getDevice = (id) =>
2466
+ /^3A.{18}$/.test(id)
2467
+ ? 'ios'
2468
+ : /^3E.{20}$/.test(id)
2469
+ ? 'web'
2470
+ : /^(.{21}|.{32})$/.test(id)
2471
+ ? 'android'
2472
+ : /^(3F|.{18}$)/.test(id)
2473
+ ? 'desktop'
2474
+ : 'unknown'
2475
+
2476
+ const updateMessageWithReceipt = (msg, receipt) => {
2477
+ msg.userReceipt = msg.userReceipt || []
2478
+ const recp = msg.userReceipt.find((m) => m.userJid === receipt.userJid)
2479
+ if (recp) {
2480
+ Object.assign(recp, receipt)
2481
+ } else {
2482
+ msg.userReceipt.push(receipt)
2483
+ }
2484
+ }
2485
+
2486
+ const updateMessageWithReaction = (msg, reaction) => {
2487
+ const authorID = (0, generics_1.getKeyAuthor)(reaction.key)
2488
+ const reactions = (msg.reactions || []).filter(
2489
+ (r) => (0, generics_1.getKeyAuthor)(r.key) !== authorID
2490
+ )
2491
+ reaction.text = reaction.text || ''
2492
+ reactions.push(reaction)
2493
+ msg.reactions = reactions
2494
+ }
2495
+
2496
+ const updateMessageWithPollUpdate = (msg, update) => {
2497
+ var _a, _b
2498
+ const authorID = (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey)
2499
+ const reactions = (msg.pollUpdates || []).filter(
2500
+ (r) => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID
2501
+ )
2502
+ if (
2503
+ (_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) ===
2504
+ null || _b === void 0
2505
+ ? void 0
2506
+ : _b.length
2507
+ ) {
2508
+ reactions.push(update)
2509
+ }
2510
+ msg.pollUpdates = reactions
2511
+ }
2512
+
2513
+ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
2514
+ var _a, _b, _c
2515
+ const opts =
2516
+ ((_a = message === null || message === void 0 ? void 0 : message.pollCreationMessage) ===
2517
+ null || _a === void 0
2518
+ ? void 0
2519
+ : _a.options) ||
2520
+ ((_b = message === null || message === void 0 ? void 0 : message.pollCreationMessageV2) ===
2521
+ null || _b === void 0
2522
+ ? void 0
2523
+ : _b.options) ||
2524
+ ((_c = message === null || message === void 0 ? void 0 : message.pollCreationMessageV3) ===
2525
+ null || _c === void 0
2526
+ ? void 0
2527
+ : _c.options) ||
2528
+ []
2529
+ const voteHashMap = opts.reduce((acc, opt) => {
2530
+ const hash = (0, crypto_2.sha256)(Buffer.from(opt.optionName || '')).toString()
2531
+ acc[hash] = {
2532
+ name: opt.optionName || '',
2533
+ voters: []
2534
+ }
2535
+ return acc
2536
+ }, {})
2537
+ for (const update of pollUpdates || []) {
2538
+ const { vote } = update
2539
+ if (!vote) {
2540
+ continue
2541
+ }
2542
+ for (const option of vote.selectedOptions || []) {
2543
+ const hash = option.toString()
2544
+ let data = voteHashMap[hash]
2545
+ if (!data) {
2546
+ voteHashMap[hash] = {
2547
+ name: 'Unknown',
2548
+ voters: []
2549
+ }
2550
+ data = voteHashMap[hash]
2551
+ }
2552
+ voteHashMap[hash].voters.push(
2553
+ (0, generics_1.getKeyAuthor)(update.pollUpdateMessageKey, meId)
2554
+ )
2555
+ }
2556
+ }
2557
+ return Object.values(voteHashMap)
2558
+ }
2559
+
2560
+ const aggregateMessageKeysNotFromMe = (keys) => {
2561
+ const keyMap = {}
2562
+ for (const { remoteJid, id, participant, fromMe } of keys) {
2563
+ if (!fromMe) {
2564
+ const uqKey = `${remoteJid}:${participant || ''}`
2565
+ if (!keyMap[uqKey]) {
2566
+ keyMap[uqKey] = {
2567
+ jid: remoteJid,
2568
+ participant: participant,
2569
+ messageIds: []
2570
+ }
2571
+ }
2572
+ keyMap[uqKey].messageIds.push(id)
2573
+ }
2574
+ }
2575
+ return Object.values(keyMap)
2576
+ }
2577
+
2578
+ const REUPLOAD_REQUIRED_STATUS = [410, 404]
2579
+
2580
+ const downloadMediaMessage = async (message, type, options, ctx) => {
2581
+ const result = await downloadMsg().catch(async (error) => {
2582
+ var _a
2583
+ if (ctx) {
2584
+ if (axios_1.default.isAxiosError(error)) {
2585
+ if (
2586
+ REUPLOAD_REQUIRED_STATUS.includes(
2587
+ (_a = error.response) === null || _a === void 0 ? void 0 : _a.status
2588
+ )
2589
+ ) {
2590
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...')
2591
+ message = await ctx.reuploadRequest(message)
2592
+ const result = await downloadMsg()
2593
+ return result
2594
+ }
2595
+ }
2596
+ }
2597
+ throw error
2598
+ })
2599
+ return result
2600
+ async function downloadMsg() {
2601
+ const mContent = extractMessageContent(message.message)
2602
+ if (!mContent) {
2603
+ throw new boom_1.Boom('No message present', { statusCode: 400, data: message })
2604
+ }
2605
+ const contentType = getContentType(mContent)
2606
+ let mediaType =
2607
+ contentType === null || contentType === void 0
2608
+ ? void 0
2609
+ : contentType.replace('Message', '')
2610
+ const media = mContent[contentType]
2611
+ if (
2612
+ !media ||
2613
+ typeof media !== 'object' ||
2614
+ (!('url' in media) && !('thumbnailDirectPath' in media))
2615
+ ) {
2616
+ throw new boom_1.Boom(`"${contentType}" message is not a media message`)
2617
+ }
2618
+ let download
2619
+ if ('thumbnailDirectPath' in media && !('url' in media)) {
2620
+ download = {
2621
+ directPath: media.thumbnailDirectPath,
2622
+ mediaKey: media.mediaKey
2623
+ }
2624
+ mediaType = 'thumbnail-link'
2625
+ } else {
2626
+ download = media
2627
+ }
2628
+ const stream = await (0, messages_media_1.downloadContentFromMessage)(
2629
+ download,
2630
+ mediaType,
2631
+ options
2632
+ )
2633
+ if (type === 'buffer') {
2634
+ const bufferArray = []
2635
+ for await (const chunk of stream) {
2636
+ bufferArray.push(chunk)
2637
+ }
2638
+ return Buffer.concat(bufferArray)
2639
+ }
2640
+ return stream
2641
+ }
2642
+ }
2643
+
2644
+ const assertMediaContent = (content) => {
2645
+ content = extractMessageContent(content)
2646
+ const mediaContent =
2647
+ (content === null || content === void 0 ? void 0 : content.documentMessage) ||
2648
+ (content === null || content === void 0 ? void 0 : content.imageMessage) ||
2649
+ (content === null || content === void 0 ? void 0 : content.videoMessage) ||
2650
+ (content === null || content === void 0 ? void 0 : content.audioMessage) ||
2651
+ (content === null || content === void 0 ? void 0 : content.stickerMessage)
2652
+ if (!mediaContent) {
2653
+ throw new boom_1.Boom('given message is not a media message', {
2654
+ statusCode: 400,
2655
+ data: content
2656
+ })
2657
+ }
2658
+ return mediaContent
2659
+ }
2660
+
2661
+ const toJid = (id) => {
2662
+ if (!id) return ''
2663
+ if (id.endsWith('@lid')) return id.replace('@lid', '@s.whatsapp.net')
2664
+ if (id.includes('@')) return id
2665
+ return `${id}@s.whatsapp.net`
2666
+ }
2667
+
2668
+ const getSenderLid = (message) => {
2669
+ const sender = message.key.participant || message.key.remoteJid
2670
+ const user = (0, WABinary_1.jidDecode)(sender)?.user || ''
2671
+ const lid = (0, WABinary_1.jidEncode)(user, 'lid')
2672
+ console.log('sender lid:', lid)
2673
+ return { jid: sender, lid }
2674
+ }
2675
+
2676
+ exports.extractUrlFromText = extractUrlFromText
2677
+ exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired
2678
+ exports.prepareWAMessageMedia = prepareWAMessageMedia
2679
+ exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent
2680
+ exports.generateForwardMessageContent = generateForwardMessageContent
2681
+ exports.generateWAMessageContent = generateWAMessageContent
2682
+ exports.generateWAMessageFromContent = generateWAMessageFromContent
2683
+ exports.generateWAMessage = generateWAMessage
2684
+ exports.getContentType = getContentType
2685
+ exports.normalizeMessageContent = normalizeMessageContent
2686
+ exports.extractMessageContent = extractMessageContent
2687
+ exports.getDevice = getDevice
2688
+ exports.updateMessageWithReceipt = updateMessageWithReceipt
2689
+ exports.updateMessageWithReaction = updateMessageWithReaction
2690
+ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate
2691
+ exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage
2692
+ exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe
2693
+ exports.downloadMediaMessage = downloadMediaMessage
2694
+ exports.assertMediaContent = assertMediaContent
2695
+ exports.toJid = toJid
2696
+ exports.getSenderLid = getSenderLid
2697
+ exports.prepareAlbumMessageContent = prepareAlbumMessageContent
2698
+ exports.processLocationThumbnail = processLocationThumbnail