@neelegirly/baileys 2.2.16

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.
Files changed (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/WAProto/WAProto.proto +5007 -0
  4. package/WAProto/index.d.ts +57712 -0
  5. package/WAProto/index.js +178969 -0
  6. package/lib/Defaults/baileys-version.json +1 -0
  7. package/lib/Defaults/index.d.ts +68 -0
  8. package/lib/Defaults/index.js +155 -0
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Signal/WASignalGroup/GroupProtocol.js +1909 -0
  11. package/lib/Signal/WASignalGroup/ciphertext_message.js +16 -0
  12. package/lib/Signal/WASignalGroup/generate-proto.sh +1 -0
  13. package/lib/Signal/WASignalGroup/group.proto +42 -0
  14. package/lib/Signal/WASignalGroup/group_cipher.js +120 -0
  15. package/lib/Signal/WASignalGroup/group_session_builder.js +46 -0
  16. package/lib/Signal/WASignalGroup/index.js +6 -0
  17. package/lib/Signal/WASignalGroup/keyhelper.js +22 -0
  18. package/lib/Signal/WASignalGroup/protobufs.js +3 -0
  19. package/lib/Signal/WASignalGroup/queue_job.js +69 -0
  20. package/lib/Signal/WASignalGroup/readme.md +6 -0
  21. package/lib/Signal/WASignalGroup/sender_chain_key.js +50 -0
  22. package/lib/Signal/WASignalGroup/sender_key_distribution_message.js +78 -0
  23. package/lib/Signal/WASignalGroup/sender_key_message.js +92 -0
  24. package/lib/Signal/WASignalGroup/sender_key_name.js +70 -0
  25. package/lib/Signal/WASignalGroup/sender_key_record.js +56 -0
  26. package/lib/Signal/WASignalGroup/sender_key_state.js +129 -0
  27. package/lib/Signal/WASignalGroup/sender_message_key.js +39 -0
  28. package/lib/Signal/libsignal.d.ts +4 -0
  29. package/lib/Signal/libsignal.js +427 -0
  30. package/lib/Socket/Client/abstract-socket-client.d.ts +15 -0
  31. package/lib/Socket/Client/abstract-socket-client.js +13 -0
  32. package/lib/Socket/Client/index.d.ts +2 -0
  33. package/lib/Socket/Client/index.js +22 -0
  34. package/lib/Socket/Client/mobile-socket-client.d.ts +12 -0
  35. package/lib/Socket/Client/mobile-socket-client.js +65 -0
  36. package/lib/Socket/Client/types.d.ts +16 -0
  37. package/lib/Socket/Client/types.js +18 -0
  38. package/lib/Socket/Client/websocket.d.ts +13 -0
  39. package/lib/Socket/Client/websocket.js +62 -0
  40. package/lib/Socket/business.d.ts +187 -0
  41. package/lib/Socket/business.js +268 -0
  42. package/lib/Socket/chats.d.ts +98 -0
  43. package/lib/Socket/chats.js +1133 -0
  44. package/lib/Socket/communities.d.ts +223 -0
  45. package/lib/Socket/communities.js +433 -0
  46. package/lib/Socket/groups.d.ts +131 -0
  47. package/lib/Socket/groups.js +352 -0
  48. package/lib/Socket/index.d.ts +191 -0
  49. package/lib/Socket/index.js +23 -0
  50. package/lib/Socket/messages-recv.d.ts +177 -0
  51. package/lib/Socket/messages-recv.js +1826 -0
  52. package/lib/Socket/messages-send.d.ts +168 -0
  53. package/lib/Socket/messages-send.js +1537 -0
  54. package/lib/Socket/mex.d.ts +2 -0
  55. package/lib/Socket/mex.js +47 -0
  56. package/lib/Socket/newsletter.d.ts +147 -0
  57. package/lib/Socket/newsletter.js +286 -0
  58. package/lib/Socket/registration.d.ts +266 -0
  59. package/lib/Socket/registration.js +166 -0
  60. package/lib/Socket/socket.d.ts +45 -0
  61. package/lib/Socket/socket.js +928 -0
  62. package/lib/Socket/usync.d.ts +37 -0
  63. package/lib/Socket/usync.js +83 -0
  64. package/lib/Store/index.d.ts +4 -0
  65. package/lib/Store/index.js +24 -0
  66. package/lib/Store/make-cache-manager-store.d.ts +14 -0
  67. package/lib/Store/make-cache-manager-store.js +90 -0
  68. package/lib/Store/make-in-memory-store.d.ts +123 -0
  69. package/lib/Store/make-in-memory-store.js +429 -0
  70. package/lib/Store/make-ordered-dictionary.d.ts +12 -0
  71. package/lib/Store/make-ordered-dictionary.js +86 -0
  72. package/lib/Store/object-repository.d.ts +10 -0
  73. package/lib/Store/object-repository.js +31 -0
  74. package/lib/Types/Auth.d.ts +120 -0
  75. package/lib/Types/Auth.js +3 -0
  76. package/lib/Types/Bussines.d.ts +20 -0
  77. package/lib/Types/Bussines.js +2 -0
  78. package/lib/Types/Call.d.ts +14 -0
  79. package/lib/Types/Call.js +3 -0
  80. package/lib/Types/Chat.d.ts +141 -0
  81. package/lib/Types/Chat.js +9 -0
  82. package/lib/Types/Contact.d.ts +20 -0
  83. package/lib/Types/Contact.js +3 -0
  84. package/lib/Types/Events.d.ts +237 -0
  85. package/lib/Types/Events.js +3 -0
  86. package/lib/Types/GroupMetadata.d.ts +66 -0
  87. package/lib/Types/GroupMetadata.js +3 -0
  88. package/lib/Types/Label.d.ts +48 -0
  89. package/lib/Types/Label.js +31 -0
  90. package/lib/Types/LabelAssociation.d.ts +35 -0
  91. package/lib/Types/LabelAssociation.js +13 -0
  92. package/lib/Types/Message.d.ts +473 -0
  93. package/lib/Types/Message.js +13 -0
  94. package/lib/Types/MexUpdates.d.ts +9 -0
  95. package/lib/Types/MexUpdates.js +18 -0
  96. package/lib/Types/Newsletter.d.ts +109 -0
  97. package/lib/Types/Newsletter.js +40 -0
  98. package/lib/Types/Product.d.ts +92 -0
  99. package/lib/Types/Product.js +3 -0
  100. package/lib/Types/Signal.d.ts +68 -0
  101. package/lib/Types/Signal.js +3 -0
  102. package/lib/Types/Socket.d.ts +122 -0
  103. package/lib/Types/Socket.js +3 -0
  104. package/lib/Types/State.d.ts +41 -0
  105. package/lib/Types/State.js +14 -0
  106. package/lib/Types/USync.d.ts +26 -0
  107. package/lib/Types/USync.js +3 -0
  108. package/lib/Types/index.d.ts +80 -0
  109. package/lib/Types/index.js +48 -0
  110. package/lib/Utils/auth-utils.d.ts +21 -0
  111. package/lib/Utils/auth-utils.js +205 -0
  112. package/lib/Utils/baileys-event-stream.d.ts +18 -0
  113. package/lib/Utils/baileys-event-stream.js +70 -0
  114. package/lib/Utils/branding.d.ts +24 -0
  115. package/lib/Utils/branding.js +209 -0
  116. package/lib/Utils/business.d.ts +29 -0
  117. package/lib/Utils/business.js +255 -0
  118. package/lib/Utils/chat-utils.d.ts +82 -0
  119. package/lib/Utils/chat-utils.js +798 -0
  120. package/lib/Utils/check-npm-version.d.ts +18 -0
  121. package/lib/Utils/check-npm-version.js +130 -0
  122. package/lib/Utils/crypto.d.ts +56 -0
  123. package/lib/Utils/crypto.js +179 -0
  124. package/lib/Utils/decode-wa-message.d.ts +41 -0
  125. package/lib/Utils/decode-wa-message.js +288 -0
  126. package/lib/Utils/event-buffer.d.ts +39 -0
  127. package/lib/Utils/event-buffer.js +565 -0
  128. package/lib/Utils/generics.d.ts +129 -0
  129. package/lib/Utils/generics.js +630 -0
  130. package/lib/Utils/history.d.ts +23 -0
  131. package/lib/Utils/history.js +110 -0
  132. package/lib/Utils/index.d.ts +22 -0
  133. package/lib/Utils/index.js +42 -0
  134. package/lib/Utils/link-preview.d.ts +23 -0
  135. package/lib/Utils/link-preview.js +120 -0
  136. package/lib/Utils/logger.d.ts +13 -0
  137. package/lib/Utils/logger.js +7 -0
  138. package/lib/Utils/lt-hash.d.ts +14 -0
  139. package/lib/Utils/lt-hash.js +58 -0
  140. package/lib/Utils/make-mutex.d.ts +9 -0
  141. package/lib/Utils/make-mutex.js +49 -0
  142. package/lib/Utils/message-retry-manager.d.ts +84 -0
  143. package/lib/Utils/message-retry-manager.js +179 -0
  144. package/lib/Utils/messages-media.d.ts +129 -0
  145. package/lib/Utils/messages-media.js +806 -0
  146. package/lib/Utils/messages.d.ts +103 -0
  147. package/lib/Utils/messages.js +1579 -0
  148. package/lib/Utils/noise-handler.d.ts +20 -0
  149. package/lib/Utils/noise-handler.js +155 -0
  150. package/lib/Utils/process-message.d.ts +49 -0
  151. package/lib/Utils/process-message.js +443 -0
  152. package/lib/Utils/signal.d.ts +42 -0
  153. package/lib/Utils/signal.js +168 -0
  154. package/lib/Utils/use-mongo-file-auth-state.d.ts +6 -0
  155. package/lib/Utils/use-mongo-file-auth-state.js +84 -0
  156. package/lib/Utils/use-multi-file-auth-state.d.ts +18 -0
  157. package/lib/Utils/use-multi-file-auth-state.js +249 -0
  158. package/lib/Utils/use-single-file-auth-state.d.ts +13 -0
  159. package/lib/Utils/use-single-file-auth-state.js +80 -0
  160. package/lib/Utils/validate-connection.d.ts +13 -0
  161. package/lib/Utils/validate-connection.js +218 -0
  162. package/lib/WABinary/constants.d.ts +30 -0
  163. package/lib/WABinary/constants.js +1316 -0
  164. package/lib/WABinary/decode.d.ts +9 -0
  165. package/lib/WABinary/decode.js +288 -0
  166. package/lib/WABinary/encode.d.ts +3 -0
  167. package/lib/WABinary/encode.js +265 -0
  168. package/lib/WABinary/generic-utils.d.ts +28 -0
  169. package/lib/WABinary/generic-utils.js +142 -0
  170. package/lib/WABinary/index.d.ts +5 -0
  171. package/lib/WABinary/index.js +25 -0
  172. package/lib/WABinary/jid-utils.d.ts +59 -0
  173. package/lib/WABinary/jid-utils.js +105 -0
  174. package/lib/WABinary/types.d.ts +22 -0
  175. package/lib/WABinary/types.js +3 -0
  176. package/lib/WAM/BinaryInfo.d.ts +16 -0
  177. package/lib/WAM/BinaryInfo.js +17 -0
  178. package/lib/WAM/constants.d.ts +47 -0
  179. package/lib/WAM/constants.js +15371 -0
  180. package/lib/WAM/encode.d.ts +3 -0
  181. package/lib/WAM/encode.js +165 -0
  182. package/lib/WAM/index.d.ts +3 -0
  183. package/lib/WAM/index.js +23 -0
  184. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +28 -0
  185. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +69 -0
  186. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  187. package/lib/WAUSync/Protocols/USyncContactProtocol.js +36 -0
  188. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +26 -0
  189. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +62 -0
  190. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +14 -0
  191. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +35 -0
  192. package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +9 -0
  193. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
  194. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +14 -0
  195. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +46 -0
  196. package/lib/WAUSync/Protocols/index.d.ts +6 -0
  197. package/lib/WAUSync/Protocols/index.js +26 -0
  198. package/lib/WAUSync/USyncQuery.d.ts +31 -0
  199. package/lib/WAUSync/USyncQuery.js +82 -0
  200. package/lib/WAUSync/USyncUser.d.ts +12 -0
  201. package/lib/WAUSync/USyncUser.js +30 -0
  202. package/lib/WAUSync/index.d.ts +3 -0
  203. package/lib/WAUSync/index.js +23 -0
  204. package/lib/index.d.ts +13 -0
  205. package/lib/index.js +33 -0
  206. package/package.json +120 -0
@@ -0,0 +1,1537 @@
1
+ "use strict"
2
+
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod }
5
+ }
6
+
7
+ Object.defineProperty(exports, "__esModule", { value: true })
8
+
9
+ const node_cache_1 = __importDefault(require("@cacheable/node-cache"))
10
+ const boom_1 = require("@hapi/boom")
11
+ const crypto_1 = require("crypto")
12
+ const WAProto_1 = require("../../WAProto")
13
+ const Defaults_1 = require("../Defaults")
14
+ const Utils_1 = require("../Utils")
15
+ const Types_1 = require("../Types")
16
+ const WABinary_1 = require("../WABinary")
17
+ const WAUSync_1 = require("../WAUSync")
18
+ const newsletter_1 = require("./newsletter")
19
+ const link_preview_1 = require("../Utils/link-preview")
20
+
21
+ const makeMessagesSocket = (config) => {
22
+ const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: axiosOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config
23
+ const baron = newsletter_1.makeNewsletterSocket(config)
24
+ const { ev, authState, processingMutex, signalRepository, upsertMessage, createCallLink, query, fetchPrivacySettings, sendNode, groupQuery, groupMetadata, groupToggleEphemeral, newsletterWMexQuery, executeUSyncQuery } = baron
25
+
26
+ const userDevicesCache = config.userDevicesCache || new node_cache_1.default({
27
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.USER_DEVICES,
28
+ useClones: false
29
+ })
30
+
31
+ // Initialize message retry manager if enabled
32
+ const messageRetryManager = enableRecentMessageCache ? new Utils_1.MessageRetryManager(logger, maxMsgRetryCount) : null
33
+
34
+ let mediaConn
35
+
36
+ const refreshMediaConn = async (forceGet = false) => {
37
+ const media = await mediaConn
38
+
39
+ if (!media || forceGet || (new Date().getTime() - media.fetchDate.getTime()) > media.ttl * 1000) {
40
+ mediaConn = (async () => {
41
+
42
+ const result = await query({
43
+ tag: 'iq',
44
+ attrs: {
45
+ type: 'set',
46
+ xmlns: 'w:m',
47
+ to: WABinary_1.S_WHATSAPP_NET,
48
+ },
49
+ content: [{ tag: 'media_conn', attrs: {} }]
50
+ })
51
+
52
+ const mediaConnNode = WABinary_1.getBinaryNodeChild(result, 'media_conn')
53
+
54
+ const node = {
55
+ hosts: WABinary_1.getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
56
+ hostname: attrs.hostname,
57
+ maxContentLengthBytes: +attrs.maxContentLengthBytes,
58
+ })),
59
+ auth: mediaConnNode.attrs.auth,
60
+ ttl: +mediaConnNode.attrs.ttl,
61
+ fetchDate: new Date()
62
+ }
63
+
64
+ logger.debug('fetched media conn')
65
+
66
+ return node
67
+ })()
68
+ }
69
+
70
+ return mediaConn
71
+ }
72
+
73
+ /**
74
+ * generic send receipt function
75
+ * used for receipts of phone call, read, delivery etc.
76
+ * */
77
+ const sendReceipt = async (jid, participant, messageIds, type) => {
78
+ const node = {
79
+ tag: 'receipt',
80
+ attrs: {
81
+ id: messageIds[0],
82
+ },
83
+ }
84
+
85
+ const isReadReceipt = type === 'read' || type === 'read-self'
86
+
87
+ if (isReadReceipt) {
88
+ node.attrs.t = Utils_1.unixTimestampSeconds().toString()
89
+ }
90
+
91
+ if (type === 'sender' && WABinary_1.isJidUser(jid)) {
92
+ node.attrs.recipient = jid
93
+ node.attrs.to = participant
94
+ }
95
+
96
+ else {
97
+ node.attrs.to = jid
98
+ if (participant) {
99
+ node.attrs.participant = participant
100
+ }
101
+ }
102
+
103
+ if (type) {
104
+ node.attrs.type = WABinary_1.isJidNewsletter(jid) ? 'read-self' : type
105
+ }
106
+
107
+ const remainingMessageIds = messageIds.slice(1)
108
+
109
+ if (remainingMessageIds.length) {
110
+ node.content = [
111
+ {
112
+ tag: 'list',
113
+ attrs: {},
114
+ content: remainingMessageIds.map(id => ({
115
+ tag: 'item',
116
+ attrs: { id }
117
+ }))
118
+ }
119
+ ]
120
+ }
121
+
122
+ logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages')
123
+
124
+ await sendNode(node)
125
+ }
126
+
127
+ /** Correctly bulk send receipts to multiple chats, participants */
128
+ const sendReceipts = async (keys, type) => {
129
+ const recps = Utils_1.aggregateMessageKeysNotFromMe(keys)
130
+
131
+ for (const { jid, participant, messageIds } of recps) {
132
+ await sendReceipt(jid, participant, messageIds, type)
133
+ }
134
+ }
135
+
136
+ /** Bulk read messages. Keys can be from different chats & participants */
137
+ const readMessages = async (keys) => {
138
+ const privacySettings = await fetchPrivacySettings()
139
+
140
+ // based on privacy settings, we have to change the read type
141
+ const readType = privacySettings.readreceipts === 'all' ? 'read' : 'read-self'
142
+
143
+ await sendReceipts(keys, readType)
144
+ }
145
+
146
+ /** Fetch image for groups, user, and newsletter **/
147
+ const profilePictureUrl = async (jid) => {
148
+ if (WABinary_1.isJidNewsletter(jid)) {
149
+
150
+ let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
151
+ input: {
152
+ key: jid,
153
+ type: 'JID',
154
+ view_role: 'GUEST'
155
+ },
156
+ fetch_viewer_metadata: true,
157
+ fetch_full_image: true,
158
+ fetch_creation_time: true
159
+ })
160
+
161
+ let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
162
+
163
+ let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
164
+
165
+ return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
166
+
167
+ }
168
+
169
+ else {
170
+ const result = await query({
171
+ tag: 'iq',
172
+ attrs: {
173
+ target: WABinary_1.jidNormalizedUser(jid),
174
+ to: WABinary_1.S_WHATSAPP_NET,
175
+ type: 'get',
176
+ xmlns: 'w:profile:picture'
177
+ },
178
+ content: [{
179
+ tag: 'picture',
180
+ attrs: {
181
+ type: 'image',
182
+ query: 'url'
183
+ }
184
+ }]
185
+ })
186
+
187
+ const child = WABinary_1.getBinaryNodeChild(result, 'picture')
188
+
189
+ return child?.attrs?.url || null
190
+ }
191
+ }
192
+
193
+ const normalizeDeviceTargetJid = (input) => {
194
+ if (!input) {
195
+ return ''
196
+ }
197
+
198
+ if (typeof input === 'string') {
199
+ return input.trim()
200
+ }
201
+
202
+ if (typeof input === 'object') {
203
+ if (typeof input.user === 'string' && typeof input.server === 'string') {
204
+ return `${input.user}@${input.server}`.trim()
205
+ }
206
+
207
+ if (typeof input.id === 'string') {
208
+ return input.id.trim()
209
+ }
210
+
211
+ if (typeof input.jid === 'string') {
212
+ return input.jid.trim()
213
+ }
214
+
215
+ if (typeof input.participant === 'string') {
216
+ return input.participant.trim()
217
+ }
218
+
219
+ if (input.id && typeof input.id === 'object' && typeof input.id.user === 'string' && typeof input.id.server === 'string') {
220
+ return `${input.id.user}@${input.id.server}`.trim()
221
+ }
222
+
223
+ if (input.jid && typeof input.jid === 'object' && typeof input.jid.user === 'string' && typeof input.jid.server === 'string') {
224
+ return `${input.jid.user}@${input.jid.server}`.trim()
225
+ }
226
+ }
227
+
228
+ return ''
229
+ }
230
+
231
+ const sanitizeGroupMetadataParticipants = (metadata) => {
232
+ if (!metadata || typeof metadata !== 'object' || !Array.isArray(metadata.participants)) {
233
+ return metadata
234
+ }
235
+
236
+ const sanitizedParticipants = metadata.participants
237
+ .map((participant) => {
238
+ const normalizedId = normalizeDeviceTargetJid(participant)
239
+
240
+ if (!normalizedId) {
241
+ return null
242
+ }
243
+
244
+ if (typeof participant === 'string') {
245
+ return { id: normalizedId }
246
+ }
247
+
248
+ if (participant && typeof participant === 'object') {
249
+ return { ...participant, id: normalizedId }
250
+ }
251
+
252
+ return { id: normalizedId }
253
+ })
254
+ .filter(Boolean)
255
+
256
+ if (sanitizedParticipants.length === metadata.participants.length) {
257
+ return metadata
258
+ }
259
+
260
+ logger.warn({
261
+ jid: metadata.id || metadata.jid,
262
+ removedParticipants: metadata.participants.length - sanitizedParticipants.length
263
+ }, 'sanitized invalid group metadata participants')
264
+
265
+ return {
266
+ ...metadata,
267
+ participants: sanitizedParticipants
268
+ }
269
+ }
270
+
271
+ /** Fetch all the devices we've to send a message to */
272
+ const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
273
+ const deviceResults = []
274
+
275
+ if (!useCache) {
276
+ logger.debug('not using cache for devices')
277
+ }
278
+
279
+ const toFetch = []
280
+
281
+ const skippedTargets = []
282
+
283
+ const normalizedInputJids = Array.from(new Set((Array.isArray(jids) ? jids : [jids]).map(normalizeDeviceTargetJid).filter(Boolean)))
284
+ const jidsWithUser = normalizedInputJids.map((jid) => {
285
+ const decoded = WABinary_1.jidDecode(jid)
286
+ const user = decoded?.user
287
+ const device = decoded?.device
288
+ const server = decoded?.server
289
+ const isExplicitDevice = typeof device === 'number' && device >= 0
290
+
291
+ if (isExplicitDevice && user) {
292
+ deviceResults.push({ user, device, server, jid })
293
+ return null
294
+ }
295
+
296
+ const normalizedJid = WABinary_1.jidNormalizedUser(jid)
297
+ if (!normalizedJid || !user) {
298
+ skippedTargets.push(String(jid || '').trim())
299
+ return null
300
+ }
301
+
302
+ return { jid: normalizedJid, user }
303
+ }).filter(Boolean)
304
+
305
+ for (const { jid, user } of jidsWithUser) {
306
+
307
+ if (useCache) {
308
+ const devices = userDevicesCache.get(user)
309
+
310
+ if (devices) {
311
+ const devicesWithJid = devices.map((d) => ({
312
+ ...d,
313
+ jid: WABinary_1.jidEncode(d.user, d.server || 's.whatsapp.net', d.device)
314
+ }))
315
+ deviceResults.push(...devicesWithJid)
316
+ logger.trace({ user }, 'using cache for devices')
317
+ }
318
+
319
+ else {
320
+ toFetch.push(jid)
321
+ }
322
+ }
323
+
324
+ else {
325
+ toFetch.push(jid)
326
+ }
327
+ }
328
+
329
+ if (skippedTargets.length) {
330
+ logger.warn({ count: skippedTargets.length, sample: skippedTargets.slice(0, 5) }, 'skipping invalid device targets')
331
+ }
332
+
333
+ if (!toFetch.length) {
334
+ return deviceResults
335
+ }
336
+
337
+ const requestedLidUsers = new Set()
338
+ for (const jid of toFetch) {
339
+ if (WABinary_1.isLidUser(jid) || WABinary_1.isHostedLidUser?.(jid)) {
340
+ const user = WABinary_1.jidDecode(jid)?.user
341
+ if (user) {
342
+ requestedLidUsers.add(user)
343
+ }
344
+ }
345
+ }
346
+
347
+ const query = new WAUSync_1.USyncQuery()
348
+ .withContext('message')
349
+ .withDeviceProtocol()
350
+ .withLIDProtocol()
351
+
352
+ for (const jid of toFetch) {
353
+ query.withUser(new WAUSync_1.USyncUser().withId(jid))
354
+ }
355
+
356
+ const result = await executeUSyncQuery(query)
357
+
358
+ if (result) {
359
+ const lidResults = Array.isArray(result?.list)
360
+ ? result.list.filter(entry => !!entry?.lid)
361
+ : []
362
+
363
+ if (lidResults.length && signalRepository?.lidMapping?.storeLIDPNMappings) {
364
+ try {
365
+ await signalRepository.lidMapping.storeLIDPNMappings(
366
+ lidResults.map(entry => ({ lid: entry.lid, pn: entry.id }))
367
+ )
368
+ } catch (error) {
369
+ logger.warn({ error, count: lidResults.length }, 'failed to store LID mappings from device query')
370
+ }
371
+ }
372
+
373
+ const extracted = Utils_1.extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me?.lid, ignoreZeroDevices)
374
+ const deviceMap = {}
375
+
376
+ for (const item of extracted) {
377
+ deviceMap[item.user] = deviceMap[item.user] || []
378
+ deviceMap[item.user].push(item)
379
+ }
380
+
381
+ for (const [user, userDevices] of Object.entries(deviceMap)) {
382
+ const prioritizeLid = requestedLidUsers.has(user)
383
+ for (const item of userDevices) {
384
+ const finalJid = WABinary_1.jidEncode(
385
+ prioritizeLid ? user : item.user,
386
+ item.server || (prioritizeLid ? 'lid' : 's.whatsapp.net'),
387
+ item.device
388
+ )
389
+ deviceResults.push({
390
+ ...item,
391
+ jid: finalJid
392
+ })
393
+ }
394
+ }
395
+
396
+ for (const key in deviceMap) {
397
+ userDevicesCache.set(key, deviceMap[key])
398
+ }
399
+ }
400
+
401
+ return deviceResults
402
+ }
403
+
404
+ /** Assert Sessions */
405
+ const assertSessions = async (jids, force) => {
406
+ let didFetchNewSession = false
407
+ let jidsRequiringFetch = []
408
+
409
+ if (force) {
410
+ jidsRequiringFetch = jids
411
+ }
412
+
413
+ else {
414
+ const addrs = jids.map(jid => (signalRepository.jidToSignalProtocolAddress(jid)))
415
+
416
+ const sessions = await authState.keys.get('session', addrs)
417
+
418
+ for (const jid of jids) {
419
+ const signalId = signalRepository
420
+ .jidToSignalProtocolAddress(jid)
421
+
422
+ if (!sessions[signalId]) {
423
+ jidsRequiringFetch.push(jid)
424
+ }
425
+ }
426
+ }
427
+
428
+ if (jidsRequiringFetch.length) {
429
+ let wireJids = [...new Set(jidsRequiringFetch)]
430
+
431
+ if (signalRepository?.lidMapping) {
432
+ const lidJids = []
433
+ const pnJids = []
434
+
435
+ for (const jid of wireJids) {
436
+ if (typeof jid === 'string' && jid.endsWith('@lid')) {
437
+ lidJids.push(jid)
438
+ } else {
439
+ pnJids.push(jid)
440
+ }
441
+ }
442
+
443
+ if (pnJids.length) {
444
+ try {
445
+ let mappedLids = []
446
+ if (typeof signalRepository.lidMapping.getLIDsForPNs === 'function') {
447
+ const mappings = await signalRepository.lidMapping.getLIDsForPNs(pnJids)
448
+ mappedLids = Array.isArray(mappings)
449
+ ? mappings.map(entry => entry?.lid).filter(Boolean)
450
+ : []
451
+ } else if (typeof signalRepository.lidMapping.getLIDForPN === 'function') {
452
+ for (const jid of pnJids) {
453
+ const mapped = await signalRepository.lidMapping.getLIDForPN(jid)
454
+ if (mapped) {
455
+ mappedLids.push(mapped)
456
+ }
457
+ }
458
+ }
459
+
460
+ wireJids = [...new Set([...lidJids, ...mappedLids, ...pnJids])]
461
+ } catch (error) {
462
+ logger.debug({ error, pnJids }, 'failed to map PN sessions to LID sessions, falling back to original JIDs')
463
+ wireJids = [...new Set([...lidJids, ...pnJids])]
464
+ }
465
+ }
466
+ }
467
+
468
+ logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions')
469
+
470
+ const result = await query({
471
+ tag: 'iq',
472
+ attrs: {
473
+ xmlns: 'encrypt',
474
+ type: 'get',
475
+ to: WABinary_1.S_WHATSAPP_NET,
476
+ },
477
+ content: [
478
+ {
479
+ tag: 'key',
480
+ attrs: {},
481
+ content: wireJids.map(jid => ({
482
+ tag: 'user',
483
+ attrs: { jid },
484
+ }))
485
+ }
486
+ ]
487
+ })
488
+
489
+ await Utils_1.parseAndInjectE2ESessions(result, signalRepository)
490
+
491
+ didFetchNewSession = true
492
+ }
493
+
494
+ return didFetchNewSession
495
+ }
496
+
497
+ /** Send Peer Operation */
498
+ const sendPeerDataOperationMessage = async (pdoMessage) => {
499
+ //TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
500
+ if (!authState.creds.me?.id) {
501
+ throw new boom_1.Boom('Not authenticated')
502
+ }
503
+
504
+ const protocolMessage = {
505
+ protocolMessage: {
506
+ peerDataOperationRequestMessage: pdoMessage,
507
+ type: WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
508
+ }
509
+ }
510
+
511
+ const meJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
512
+
513
+ const msgId = await relayMessage(meJid, protocolMessage, {
514
+ additionalAttributes: {
515
+ category: 'peer',
516
+ // eslint-disable-next-line camelcase
517
+ push_priority: 'high_force',
518
+ },
519
+ })
520
+
521
+ return msgId
522
+ }
523
+
524
+ const createParticipantNodes = async (jids, message, extraAttrs) => {
525
+ const patched = await patchMessageBeforeSending(message, jids)
526
+ const bytes = Utils_1.encodeWAMessage(patched)
527
+
528
+ let shouldIncludeDeviceIdentity = false
529
+
530
+ const nodes = await Promise.all(jids.map(async (jid) => {
531
+ const { type, ciphertext } = await signalRepository.encryptMessage({ jid, data: bytes })
532
+
533
+ if (type === 'pkmsg') {
534
+ shouldIncludeDeviceIdentity = true
535
+ }
536
+
537
+ const node = {
538
+ tag: 'to',
539
+ attrs: { jid },
540
+ content: [{
541
+ tag: 'enc',
542
+ attrs: {
543
+ v: '2',
544
+ type,
545
+ ...extraAttrs || {}
546
+ },
547
+ content: ciphertext
548
+ }]
549
+ }
550
+
551
+ return node
552
+ }))
553
+
554
+ return {
555
+ nodes,
556
+ shouldIncludeDeviceIdentity
557
+ }
558
+ }
559
+
560
+ const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes, AI = true }) => {
561
+ const meId = authState.creds.me.id
562
+ const meLid = authState.creds.me?.lid
563
+
564
+ let didPushAdditional = false
565
+ let shouldIncludeDeviceIdentity = false
566
+
567
+ const { user, server } = WABinary_1.jidDecode(jid)
568
+
569
+ const statusJid = 'status@broadcast'
570
+ const isGroup = server === 'g.us'
571
+ const isPrivate = server === 's.whatsapp.net'
572
+ const isNewsletter = server == 'newsletter'
573
+ const isStatus = jid === statusJid
574
+ const isLid = server === 'lid'
575
+
576
+ msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
577
+ useUserDevicesCache = useUserDevicesCache !== false
578
+ useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
579
+
580
+ const participants = []
581
+ const destinationJid = (!isStatus) ? WABinary_1.jidEncode(user, isLid ? 'lid' : isGroup ? 'g.us' : isNewsletter ? 'newsletter' : 's.whatsapp.net') : statusJid
582
+ const binaryNodeContent = []
583
+ const devices = []
584
+
585
+ const meMsg = {
586
+ deviceSentMessage: {
587
+ destinationJid,
588
+ message
589
+ },
590
+ messageContextInfo: message.messageContextInfo || {}
591
+ }
592
+
593
+ const extraAttrs = {}
594
+
595
+ const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
596
+
597
+ const messages = Utils_1.normalizeMessageContent(message)
598
+
599
+ const buttonType = getButtonType(messages)
600
+ const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
601
+
602
+
603
+ if (participant) {
604
+ // when the retry request is not for a group
605
+ // only send to the specific device that asked for a retry
606
+ // otherwise the message is sent out to every device that should be a recipient
607
+ if (!isGroup && !isStatus) {
608
+ additionalAttributes = { ...additionalAttributes, 'device_fanout': 'false' }
609
+ }
610
+
611
+ const { user, device } = WABinary_1.jidDecode(participant.jid)
612
+
613
+ devices.push({ user, device })
614
+ }
615
+
616
+ await authState.keys.transaction(async () => {
617
+ const mediaType = getMediaType(message)
618
+
619
+ if (mediaType) {
620
+ extraAttrs['mediatype'] = mediaType
621
+ }
622
+
623
+ if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
624
+ extraAttrs['decrypt-fail'] = 'hide'
625
+ }
626
+
627
+ if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
628
+ extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options'
629
+ }
630
+
631
+ if (isGroup || isStatus) {
632
+ const [groupData, senderKeyMap] = await Promise.all([
633
+ (async () => {
634
+ let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
635
+
636
+ groupData = sanitizeGroupMetadataParticipants(groupData)
637
+
638
+ if (groupData && Array.isArray(groupData?.participants)) {
639
+ logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
640
+ }
641
+
642
+ else if (!isStatus) {
643
+ groupData = await groupMetadata(jid)
644
+ groupData = sanitizeGroupMetadataParticipants(groupData)
645
+ }
646
+
647
+ return groupData
648
+ })(),
649
+
650
+ (async () => {
651
+ if (!participant && !isStatus) {
652
+ const result = await authState.keys.get('sender-key-memory', [jid])
653
+ return result[jid] || {}
654
+ }
655
+
656
+ return {}
657
+
658
+ })()
659
+ ])
660
+
661
+ if (!participant) {
662
+ const participantsList = []
663
+ if (isStatus) {
664
+ if (statusJidList?.length) {
665
+ participantsList.push(...statusJidList)
666
+ }
667
+ } else {
668
+ let groupAddressingMode = 'lid'
669
+ if (groupData) {
670
+ participantsList.push(...groupData.participants.map(p => normalizeDeviceTargetJid(p)).filter(Boolean))
671
+ groupAddressingMode = groupData?.addressingMode || groupAddressingMode
672
+ }
673
+ additionalAttributes = {
674
+ ...additionalAttributes,
675
+ addressing_mode: groupAddressingMode
676
+ }
677
+ }
678
+
679
+ const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
680
+ devices.push(...additionalDevices)
681
+ }
682
+
683
+ if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
684
+ additionalAttributes = {
685
+ ...additionalAttributes,
686
+ expiration: groupData.ephemeralDuration.toString()
687
+ }
688
+ }
689
+
690
+ const patched = await patchMessageBeforeSending(message)
691
+ if (Array.isArray(patched)) {
692
+ throw new boom_1.Boom('Per-jid patching is not supported in groups')
693
+ }
694
+ const bytes = Utils_1.encodeWAMessage(patched)
695
+ const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid'
696
+ const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
697
+
698
+ const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
699
+ group: destinationJid,
700
+ data: bytes,
701
+ meId: groupSenderIdentity,
702
+ })
703
+
704
+ const senderKeyRecipients = []
705
+
706
+ for (const device of devices) {
707
+ const deviceJid = device.jid || WABinary_1.jidEncode(device.user, device.server || 's.whatsapp.net', device.device)
708
+ const hasKey = !!senderKeyMap[deviceJid]
709
+ if ((!hasKey || !!participant)
710
+ && !WABinary_1.isHostedLidUser?.(deviceJid)
711
+ && !WABinary_1.isHostedPnUser?.(deviceJid)
712
+ && device.device !== 99) {
713
+ senderKeyRecipients.push(deviceJid)
714
+ senderKeyMap[deviceJid] = true
715
+ }
716
+ }
717
+
718
+ if (senderKeyRecipients.length) {
719
+ logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key')
720
+ const senderKeyMsg = {
721
+ senderKeyDistributionMessage: {
722
+ axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
723
+ groupId: destinationJid
724
+ }
725
+ }
726
+
727
+ await assertSessions(senderKeyRecipients)
728
+
729
+ const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs)
730
+
731
+ shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity
732
+
733
+ participants.push(...result.nodes)
734
+ }
735
+
736
+ binaryNodeContent.push({
737
+ tag: 'enc',
738
+ attrs: { v: '2', type: 'skmsg', ...extraAttrs },
739
+ content: ciphertext
740
+ })
741
+
742
+ await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
743
+ }
744
+
745
+ else if (isNewsletter) {
746
+ // Message edit
747
+ if (message.protocolMessage?.editedMessage) {
748
+ msgId = message.protocolMessage.key?.id
749
+ message = message.protocolMessage.editedMessage
750
+ }
751
+
752
+ // Message delete
753
+ if (message.protocolMessage?.type === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
754
+ msgId = message.protocolMessage.key?.id
755
+ message = {}
756
+ }
757
+
758
+ const patched = await patchMessageBeforeSending(message, [])
759
+ const bytes = Utils_1.encodeNewsletterMessage(patched)
760
+
761
+ binaryNodeContent.push({
762
+ tag: 'plaintext',
763
+ attrs: extraAttrs ? extraAttrs : {},
764
+ content: bytes
765
+ })
766
+ }
767
+
768
+ else {
769
+ const { user: meUser } = WABinary_1.jidDecode(meId)
770
+
771
+ if (!participant) {
772
+ devices.push({ user })
773
+ if (user !== meUser) {
774
+ devices.push({ user: meUser })
775
+ }
776
+
777
+ if (additionalAttributes?.['category'] !== 'peer') {
778
+ const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true)
779
+
780
+ devices.push(...additionalDevices)
781
+ }
782
+ }
783
+
784
+ const allJids = []
785
+ const meJids = []
786
+ const otherJids = []
787
+
788
+ for (const { user, device } of devices) {
789
+ const isMe = user === meUser
790
+ const jid = WABinary_1.jidEncode(isMe && isLid ? authState.creds?.me?.lid?.split(':')[0] || user : user, isLid ? 'lid' : 's.whatsapp.net', device)
791
+
792
+ if (isMe) {
793
+ meJids.push(jid)
794
+ }
795
+
796
+ else {
797
+ otherJids.push(jid)
798
+ }
799
+
800
+ allJids.push(jid)
801
+ }
802
+
803
+ await assertSessions(allJids, false)
804
+
805
+ const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
806
+ createParticipantNodes(meJids, meMsg, extraAttrs),
807
+ createParticipantNodes(otherJids, message, extraAttrs)
808
+ ])
809
+
810
+ participants.push(...meNodes)
811
+
812
+ participants.push(...otherNodes)
813
+
814
+ shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
815
+ }
816
+
817
+ if (participants.length) {
818
+ if (additionalAttributes?.['category'] === 'peer') {
819
+ const peerNode = participants[0]?.content?.[0]
820
+
821
+ if (peerNode) {
822
+ binaryNodeContent.push(peerNode) // push only enc
823
+ }
824
+ }
825
+
826
+ else {
827
+ binaryNodeContent.push({
828
+ tag: 'participants',
829
+ attrs: {},
830
+ content: participants
831
+ })
832
+ }
833
+ }
834
+
835
+ const stanza = {
836
+ tag: 'message',
837
+ attrs: {
838
+ id: msgId,
839
+ type: getTypeMessage(message),
840
+ ...(additionalAttributes || {})
841
+ },
842
+ content: binaryNodeContent
843
+ }
844
+
845
+ // if the participant to send to is explicitly specified (generally retry recp)
846
+ // ensure the message is only sent to that person
847
+ // if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
848
+ if (participant) {
849
+ if (WABinary_1.isJidGroup(destinationJid)) {
850
+ stanza.attrs.to = destinationJid
851
+ stanza.attrs.participant = participant.jid
852
+ }
853
+
854
+ else if (WABinary_1.areJidsSameUser(participant.jid, meId)) {
855
+ stanza.attrs.to = participant.jid
856
+ stanza.attrs.recipient = destinationJid
857
+ }
858
+
859
+ else {
860
+ stanza.attrs.to = participant.jid
861
+ }
862
+ }
863
+
864
+ else {
865
+ stanza.attrs.to = destinationJid
866
+ }
867
+
868
+ if (shouldIncludeDeviceIdentity) {
869
+ stanza.content.push({
870
+ tag: 'device-identity',
871
+ attrs: {},
872
+ content: Utils_1.encodeSignedDeviceIdentity(authState.creds.account, true)
873
+ })
874
+
875
+ logger.debug({ jid }, 'adding device identity')
876
+ }
877
+
878
+ if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
879
+ stanza.content.push({
880
+ tag: 'multicast',
881
+ attrs: {}
882
+ })
883
+ }
884
+
885
+ if (pollMessage || messages.eventMessage) {
886
+ stanza.content.push({
887
+ tag: 'meta',
888
+ attrs: messages.eventMessage ? {
889
+ event_type: 'creation'
890
+ } : isNewsletter ? {
891
+ polltype: 'creation',
892
+ contenttype: pollMessage?.pollContentType === 2 ? 'image' : 'text'
893
+ } : {
894
+ polltype: 'creation'
895
+ }
896
+ })
897
+ }
898
+
899
+ if (!isNewsletter && buttonType) {
900
+ const buttonsNode = getButtonArgs(messages)
901
+ const filteredButtons = WABinary_1.getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
902
+
903
+ if (filteredButtons) {
904
+ stanza.content.push(...additionalNodes)
905
+ didPushAdditional = true
906
+ }
907
+
908
+ else {
909
+ stanza.content.push(buttonsNode)
910
+ }
911
+ }
912
+
913
+ if (AI && isPrivate) {
914
+ const botNode = {
915
+ tag: 'bot',
916
+ attrs: {
917
+ biz_bot: '1'
918
+ }
919
+ }
920
+
921
+ const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
922
+
923
+ if (filteredBizBot) {
924
+ stanza.content.push(...additionalNodes)
925
+ didPushAdditional = true
926
+ }
927
+
928
+ else {
929
+ stanza.content.push(botNode)
930
+ }
931
+ }
932
+
933
+ if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
934
+ stanza.content.push(...additionalNodes)
935
+ }
936
+
937
+ logger.debug({ msgId }, `sending message to ${participants.length} devices`)
938
+
939
+ await sendNode(stanza)
940
+
941
+ // Add message to retry cache if enabled
942
+ if (messageRetryManager && !participant) {
943
+ messageRetryManager.addRecentMessage(destinationJid, msgId, message)
944
+ }
945
+ })
946
+
947
+ return msgId
948
+ }
949
+
950
+ const getTypeMessage = (msg) => {
951
+ const message = Utils_1.normalizeMessageContent(msg)
952
+ if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
953
+ return 'poll'
954
+ }
955
+ else if (message.reactionMessage) {
956
+ return 'reaction'
957
+ }
958
+ else if (message.eventMessage) {
959
+ return 'event'
960
+ }
961
+ else if (getMediaType(message)) {
962
+ return 'media'
963
+ }
964
+ else {
965
+ return 'text'
966
+ }
967
+ }
968
+
969
+ const getMediaType = (message) => {
970
+ if (message.imageMessage) {
971
+ return 'image'
972
+ }
973
+ else if (message.stickerMessage) {
974
+ return message.stickerMessage.isLottie ? '1p_sticker' : message.stickerMessage.isAvatar ? 'avatar_sticker' : 'sticker'
975
+ }
976
+ else if (message.videoMessage) {
977
+ return message.videoMessage.gifPlayback ? 'gif' : 'video'
978
+ }
979
+ else if (message.audioMessage) {
980
+ return message.audioMessage.ptt ? 'ptt' : 'audio'
981
+ }
982
+ else if (message.ptvMessage) {
983
+ return 'ptv'
984
+ }
985
+ else if (message.contactMessage) {
986
+ return 'vcard'
987
+ }
988
+ else if (message.documentMessage) {
989
+ return 'document'
990
+ }
991
+ else if (message.stickerPackMessage) {
992
+ return 'sticker_pack'
993
+ }
994
+ else if (message.contactsArrayMessage) {
995
+ return 'contact_array'
996
+ }
997
+ else if (message.locationMessage) {
998
+ return 'location'
999
+ }
1000
+ else if (message.liveLocationMessage) {
1001
+ return 'livelocation'
1002
+ }
1003
+ else if (message.listMessage) {
1004
+ return 'list'
1005
+ }
1006
+ else if (message.listResponseMessage) {
1007
+ return 'list_response'
1008
+ }
1009
+ else if (message.buttonsResponseMessage) {
1010
+ return 'buttons_response'
1011
+ }
1012
+ else if (message.orderMessage) {
1013
+ return 'order'
1014
+ }
1015
+ else if (message.productMessage) {
1016
+ return 'product'
1017
+ }
1018
+ else if (message.interactiveResponseMessage) {
1019
+ return 'native_flow_response'
1020
+ }
1021
+ else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
1022
+ return 'cataloglink'
1023
+ }
1024
+ else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
1025
+ return 'productlink'
1026
+ }
1027
+ else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
1028
+ return 'url'
1029
+ }
1030
+ }
1031
+
1032
+ const getButtonType = (message) => {
1033
+ if (message.listMessage) {
1034
+ return 'list'
1035
+ }
1036
+ else if (message.buttonsMessage) {
1037
+ return 'buttons'
1038
+ }
1039
+ else if(message.interactiveMessage?.nativeFlowMessage) {
1040
+ return 'native_flow'
1041
+ }
1042
+ }
1043
+
1044
+ const getButtonArgs = (message) => {
1045
+ const nativeFlow = message.interactiveMessage?.nativeFlowMessage
1046
+ const firstButtonName = nativeFlow?.buttons?.[0]?.name
1047
+ const nativeFlowSpecials = [
1048
+ 'mpm', 'cta_catalog', 'send_location',
1049
+ 'call_permission_request', 'wa_payment_transaction_details',
1050
+ 'automated_greeting_message_view_catalog'
1051
+ ]
1052
+
1053
+ if (nativeFlow && (firstButtonName === 'review_and_pay' || firstButtonName === 'payment_info')) {
1054
+ return {
1055
+ tag: 'biz',
1056
+ attrs: {
1057
+ native_flow_name: firstButtonName === 'review_and_pay' ? 'order_details' : firstButtonName
1058
+ }
1059
+ }
1060
+ } else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
1061
+ // Only works for WhatsApp Original, not WhatsApp Business
1062
+ return {
1063
+ tag: 'biz',
1064
+ attrs: {},
1065
+ content: [{
1066
+ tag: 'interactive',
1067
+ attrs: {
1068
+ type: 'native_flow',
1069
+ v: '1'
1070
+ },
1071
+ content: [{
1072
+ tag: 'native_flow',
1073
+ attrs: {
1074
+ v: '2',
1075
+ name: firstButtonName
1076
+ }
1077
+ }]
1078
+ }]
1079
+ }
1080
+ } else if (nativeFlow || message.buttonsMessage) {
1081
+ // It works for whatsapp original and whatsapp business
1082
+ return {
1083
+ tag: 'biz',
1084
+ attrs: {},
1085
+ content: [{
1086
+ tag: 'interactive',
1087
+ attrs: {
1088
+ type: 'native_flow',
1089
+ v: '1'
1090
+ },
1091
+ content: [{
1092
+ tag: 'native_flow',
1093
+ attrs: {
1094
+ v: '9',
1095
+ name: 'mixed'
1096
+ }
1097
+ }]
1098
+ }]
1099
+ }
1100
+ } else if (message.listMessage) {
1101
+ return {
1102
+ tag: 'biz',
1103
+ attrs: {},
1104
+ content: [{
1105
+ tag: 'list',
1106
+ attrs: {
1107
+ v: '2',
1108
+ type: 'product_list'
1109
+ }
1110
+ }]
1111
+ }
1112
+ } else {
1113
+ return {
1114
+ tag: 'biz',
1115
+ attrs: {}
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ const getPrivacyTokens = async (jids) => {
1121
+ const t = Utils_1.unixTimestampSeconds().toString()
1122
+
1123
+ const result = await query({
1124
+ tag: 'iq',
1125
+ attrs: {
1126
+ to: WABinary_1.S_WHATSAPP_NET,
1127
+ type: 'set',
1128
+ xmlns: 'privacy'
1129
+ },
1130
+ content: [
1131
+ {
1132
+ tag: 'tokens',
1133
+ attrs: {},
1134
+ content: jids.map(jid => ({
1135
+ tag: 'token',
1136
+ attrs: {
1137
+ jid: WABinary_1.jidNormalizedUser(jid),
1138
+ t,
1139
+ type: 'trusted_contact'
1140
+ }
1141
+ }))
1142
+ }
1143
+ ]
1144
+ })
1145
+
1146
+ return result
1147
+ }
1148
+
1149
+ const getEphemeralGroup = (jid) => {
1150
+ if (!WABinary_1.isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
1151
+
1152
+ return groupQuery(jid, 'get', [{
1153
+ tag: 'query',
1154
+ attrs: {
1155
+ request: 'interactive'
1156
+ }
1157
+ }])
1158
+ .then((groups) => WABinary_1.getBinaryNodeChild(groups, 'group'))
1159
+ .then((metadata) => WABinary_1.getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
1160
+ }
1161
+
1162
+ /**
1163
+ * Update Member Label
1164
+ */
1165
+ const updateMemberLabel = (jid, memberLabel) => {
1166
+ return relayMessage(
1167
+ jid,
1168
+ {
1169
+ protocolMessage: {
1170
+ type: WAProto_1.proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
1171
+ memberLabel: {
1172
+ label: memberLabel?.slice(0, 30),
1173
+ labelTimestamp: Utils_1.unixTimestampSeconds()
1174
+ }
1175
+ }
1176
+ },
1177
+ {
1178
+ additionalNodes: [
1179
+ {
1180
+ tag: 'meta',
1181
+ attrs: {
1182
+ tag_reason: 'user_update',
1183
+ appdata: 'member_tag'
1184
+ },
1185
+ content: undefined
1186
+ }
1187
+ ]
1188
+ }
1189
+ )
1190
+ }
1191
+
1192
+ const waUploadToServer = Utils_1.getWAUploadToServer(config, refreshMediaConn)
1193
+
1194
+ const waitForMsgMediaUpdate = Utils_1.bindWaitForEvent(ev, 'messages.media-update')
1195
+
1196
+ return {
1197
+ ...baron,
1198
+ getPrivacyTokens,
1199
+ assertSessions,
1200
+ relayMessage,
1201
+ sendReceipt,
1202
+ sendReceipts,
1203
+ readMessages,
1204
+ profilePictureUrl,
1205
+ getUSyncDevices,
1206
+ refreshMediaConn,
1207
+ waUploadToServer,
1208
+ getEphemeralGroup,
1209
+ fetchPrivacySettings,
1210
+ createParticipantNodes,
1211
+ sendPeerDataOperationMessage,
1212
+ messageRetryManager,
1213
+ updateMemberLabel,
1214
+ updateMediaMessage: async (message) => {
1215
+ const content = Utils_1.assertMediaContent(message.message)
1216
+ const mediaKey = content.mediaKey
1217
+ const meId = authState.creds.me.id
1218
+ const node = await Utils_1.encryptMediaRetryRequest(message.key, mediaKey, meId)
1219
+ let error = undefined
1220
+
1221
+ await Promise.all([
1222
+ sendNode(node),
1223
+ waitForMsgMediaUpdate(async (update) => {
1224
+ const result = update.find(c => c.key.id === message.key.id)
1225
+ if (result) {
1226
+ if (result.error) {
1227
+ error = result.error
1228
+ }
1229
+
1230
+ else {
1231
+ try {
1232
+ const media = await Utils_1.decryptMediaRetryData(result.media, mediaKey, result.key.id)
1233
+
1234
+ if (media.result !== WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS) {
1235
+ const resultStr = WAProto_1.proto.MediaRetryNotification.ResultType[media.result]
1236
+
1237
+ throw new boom_1.Boom(`Media re-upload failed by device (${resultStr})`, { data: media, statusCode: Utils_1.getStatusCodeForMediaRetry(media.result) || 404 })
1238
+ }
1239
+
1240
+ content.directPath = media.directPath
1241
+
1242
+ content.url = Utils_1.getUrlFromDirectPath(content.directPath)
1243
+
1244
+ logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful')
1245
+ }
1246
+
1247
+ catch (err) {
1248
+ error = err
1249
+ }
1250
+ }
1251
+
1252
+ return true
1253
+ }
1254
+ })
1255
+ ])
1256
+
1257
+ if (error) {
1258
+ throw error
1259
+ }
1260
+
1261
+ ev.emit('messages.update', [
1262
+ { key: message.key, update: { message: message.message } }
1263
+ ])
1264
+
1265
+ return message
1266
+ },
1267
+ sendStatusMentions: async (content, jids = []) => {
1268
+ const userJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
1269
+ let allUsers = new Set()
1270
+ allUsers.add(userJid)
1271
+
1272
+ for (const id of jids) {
1273
+ const isGroup = WABinary_1.isJidGroup(id)
1274
+ const isPrivate = WABinary_1.isJidUser(id)
1275
+
1276
+ if (isGroup) {
1277
+ try {
1278
+ const metadata = sanitizeGroupMetadataParticipants(await cachedGroupMetadata(id) || await groupMetadata(id))
1279
+ const participants = metadata.participants.map(p => WABinary_1.jidNormalizedUser(p.id))
1280
+ participants.forEach(jid => allUsers.add(jid))
1281
+ } catch (error) {
1282
+ logger.error(`Error getting metadata for group ${id}: ${error}`)
1283
+ }
1284
+ } else if (isPrivate) {
1285
+ allUsers.add(WABinary_1.jidNormalizedUser(id))
1286
+ }
1287
+ }
1288
+
1289
+ const uniqueUsers = Array.from(allUsers)
1290
+ const getRandomHexColor = () => "#" + Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0")
1291
+
1292
+ const isMedia = content.image || content.video || content.audio
1293
+ const isAudio = !!content.audio
1294
+
1295
+ const messageContent = { ...content }
1296
+
1297
+ if (isMedia && !isAudio) {
1298
+ if (messageContent.text) {
1299
+ messageContent.caption = messageContent.text
1300
+
1301
+ delete messageContent.text
1302
+ }
1303
+
1304
+ delete messageContent.ptt
1305
+ delete messageContent.font
1306
+ delete messageContent.backgroundColor
1307
+ delete messageContent.textColor
1308
+ }
1309
+
1310
+ if (isAudio) {
1311
+ delete messageContent.text
1312
+ delete messageContent.caption
1313
+ delete messageContent.font
1314
+ delete messageContent.textColor
1315
+ }
1316
+
1317
+ const font = !isMedia ? (content.font || Math.floor(Math.random() * 9)) : undefined
1318
+ const textColor = !isMedia ? (content.textColor || getRandomHexColor()) : undefined
1319
+ const backgroundColor = (!isMedia || isAudio) ? (content.backgroundColor || getRandomHexColor()) : undefined
1320
+ const ptt = isAudio ? (typeof content.ptt === 'boolean' ? content.ptt : true) : undefined
1321
+
1322
+ let msg
1323
+ let mediaHandle
1324
+ try {
1325
+ msg = await Utils_1.generateWAMessage(WABinary_1.STORIES_JID, messageContent, {
1326
+ logger,
1327
+ userJid,
1328
+ getUrlInfo: text => link_preview_1.getUrlInfo(text, {
1329
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
1330
+ fetchOpts: { timeout: 3000, ...axiosOptions || {} },
1331
+ logger,
1332
+ uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
1333
+ }),
1334
+ upload: async (encFilePath, opts) => {
1335
+ const up = await waUploadToServer(encFilePath, { ...opts })
1336
+ mediaHandle = up.handle
1337
+ return up
1338
+ },
1339
+ mediaCache: config.mediaCache,
1340
+ options: config.options,
1341
+ font,
1342
+ textColor,
1343
+ backgroundColor,
1344
+ ptt
1345
+ })
1346
+ } catch (error) {
1347
+ logger.error(`Error generating message: ${error}`)
1348
+ throw error
1349
+ }
1350
+
1351
+ await relayMessage(WABinary_1.STORIES_JID, msg.message, {
1352
+ messageId: msg.key.id,
1353
+ statusJidList: uniqueUsers,
1354
+ additionalNodes: [
1355
+ {
1356
+ tag: 'meta',
1357
+ attrs: {},
1358
+ content: [
1359
+ {
1360
+ tag: 'mentioned_users',
1361
+ attrs: {},
1362
+ content: jids.map(jid => ({
1363
+ tag: 'to',
1364
+ attrs: { jid: WABinary_1.jidNormalizedUser(jid) }
1365
+ }))
1366
+ }]
1367
+ }]
1368
+ })
1369
+
1370
+ for (const id of jids) {
1371
+ try {
1372
+ const normalizedId = WABinary_1.jidNormalizedUser(id)
1373
+ const isPrivate = WABinary_1.isJidUser(normalizedId)
1374
+ const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage'
1375
+
1376
+ const protocolMessage = {
1377
+ [type]: {
1378
+ message: {
1379
+ protocolMessage: {
1380
+ key: msg.key,
1381
+ type: 25
1382
+ }
1383
+ }
1384
+ },
1385
+ messageContextInfo: {
1386
+ messageSecret: crypto_1.randomBytes(32)
1387
+ }
1388
+ }
1389
+
1390
+ const statusMsg = await Utils_1.generateWAMessageFromContent(normalizedId,
1391
+ protocolMessage,
1392
+ {}
1393
+ )
1394
+
1395
+ await relayMessage(
1396
+ normalizedId,
1397
+ statusMsg.message,
1398
+ {
1399
+ additionalNodes: [{
1400
+ tag: 'meta',
1401
+ attrs: isPrivate ?
1402
+ { is_status_mention: 'true' } :
1403
+ { is_group_status_mention: 'true' }
1404
+ }]
1405
+ }
1406
+ )
1407
+
1408
+ await Utils_1.delay(2000)
1409
+ } catch (error) {
1410
+ logger.error(`Error sending to ${id}: ${error}`)
1411
+ }
1412
+ }
1413
+
1414
+ return msg
1415
+ },
1416
+ sendMessage: async (jid, content, options = {}) => {
1417
+ const userJid = authState.creds.me.id
1418
+ const additionalAttributes = {}
1419
+
1420
+ if (!options.ephemeralExpiration) {
1421
+ if (WABinary_1.isJidGroup(jid)) {
1422
+ const expiration = await getEphemeralGroup(jid)
1423
+ options.ephemeralExpiration = expiration
1424
+ }
1425
+ }
1426
+
1427
+ if (typeof content === 'object' &&
1428
+ 'disappearingMessagesInChat' in content &&
1429
+ typeof content['disappearingMessagesInChat'] !== 'undefined' &&
1430
+ WABinary_1.isJidGroup(jid)) {
1431
+
1432
+ const { disappearingMessagesInChat } = content
1433
+
1434
+ const value = typeof disappearingMessagesInChat === 'boolean' ?
1435
+ (disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
1436
+ disappearingMessagesInChat
1437
+
1438
+ await groupToggleEphemeral(jid, value)
1439
+ }
1440
+
1441
+ else if (typeof content === 'object' && 'album' in content && content.album) {
1442
+ const albumMsg = await Utils_1.prepareAlbumMessageContent(jid, content.album, {
1443
+ baron: {
1444
+ relayMessage,
1445
+ waUploadToServer
1446
+ },
1447
+ userJid: userJid,
1448
+ ...options
1449
+ })
1450
+
1451
+ for (const media of albumMsg) {
1452
+ await Utils_1.delay(options.delay || 500)
1453
+ await relayMessage(jid, media.message, { messageId: media.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
1454
+ }
1455
+
1456
+ return albumMsg
1457
+ }
1458
+
1459
+ else {
1460
+ let mediaHandle
1461
+
1462
+ const fullMsg = await Utils_1.generateWAMessage(jid, content, {
1463
+ logger,
1464
+ userJid,
1465
+ getUrlInfo: text => link_preview_1.getUrlInfo(text, {
1466
+ thumbnailWidth: linkPreviewImageThumbnailWidth,
1467
+ fetchOpts: {
1468
+ timeout: 3000,
1469
+ ...axiosOptions || {}
1470
+ },
1471
+ logger,
1472
+ uploadImage: generateHighQualityLinkPreview
1473
+ ? waUploadToServer
1474
+ : undefined
1475
+ }),
1476
+ getProfilePicUrl: profilePictureUrl,
1477
+ getCallLink: createCallLink,
1478
+ upload: async (encFilePath, opts) => {
1479
+ const up = await waUploadToServer(encFilePath, { ...opts, newsletter: WABinary_1.isJidNewsletter(jid) })
1480
+ mediaHandle = up.handle
1481
+ return up
1482
+ },
1483
+ mediaCache: config.mediaCache,
1484
+ options: config.options,
1485
+ messageId: Utils_1.generateMessageID(userJid),
1486
+ ...options,
1487
+ })
1488
+
1489
+ const isPin = 'pin' in content && !!content.pin
1490
+ const isEdit = 'edit' in content && !!content.edit
1491
+ const isDelete = 'delete' in content && !!content.delete
1492
+ const isKeep = 'keep' in content && !!content.keep && content.keep?.type === 2
1493
+
1494
+ if (isDelete || isKeep) {
1495
+ // if the chat is a group, and I am not the author, then delete the message as an admin
1496
+ if (WABinary_1.isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe || WABinary_1.isJidNewsletter(jid)) {
1497
+ additionalAttributes.edit = '8'
1498
+ }
1499
+
1500
+ else {
1501
+ additionalAttributes.edit = '7'
1502
+ }
1503
+ }
1504
+
1505
+ else if (isEdit) {
1506
+ additionalAttributes.edit = WABinary_1.isJidNewsletter(jid) ? '3' : '1'
1507
+ }
1508
+
1509
+ else if (isPin) {
1510
+ additionalAttributes.edit = '2'
1511
+ }
1512
+
1513
+ if (mediaHandle) {
1514
+ additionalAttributes['media_id'] = mediaHandle
1515
+ }
1516
+
1517
+ if ('cachedGroupMetadata' in options) {
1518
+ console.warn('cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config.')
1519
+ }
1520
+
1521
+ await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
1522
+
1523
+ if (config.emitOwnEvents) {
1524
+ process.nextTick(() => {
1525
+ processingMutex.mutex(() => (upsertMessage(fullMsg, 'append')))
1526
+ })
1527
+ }
1528
+
1529
+ return fullMsg
1530
+ }
1531
+ }
1532
+ }
1533
+ }
1534
+
1535
+ module.exports = {
1536
+ makeMessagesSocket
1537
+ }