@hansaka02/baileys 7.3.2 → 7.3.6

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 (210) hide show
  1. package/lib/Defaults/baileys-version.json +2 -2
  2. package/lib/Defaults/connection.js +51 -0
  3. package/lib/Defaults/constants.js +74 -0
  4. package/lib/Defaults/history.js +19 -0
  5. package/lib/Defaults/index.js +36 -142
  6. package/lib/Defaults/media.js +48 -0
  7. package/lib/Defaults/prefix.js +18 -0
  8. package/lib/Signal/Group/group-session-builder.js +10 -42
  9. package/lib/Signal/Group/group_cipher.js +9 -6
  10. package/lib/Signal/Group/index.js +39 -53
  11. package/lib/Signal/Group/keyhelper.js +8 -41
  12. package/lib/Signal/Group/sender-chain-key.js +5 -18
  13. package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
  14. package/lib/Signal/Group/sender-key-message.js +12 -8
  15. package/lib/Signal/Group/sender-key-record.js +7 -16
  16. package/lib/Signal/Group/sender-key-state.js +15 -61
  17. package/lib/Signal/Group/sender-message-key.js +2 -2
  18. package/lib/Signal/libsignal.js +237 -177
  19. package/lib/Signal/lid-mapping.js +128 -71
  20. package/lib/Socket/Client/types.js +2 -2
  21. package/lib/Socket/Client/websocket.js +25 -16
  22. package/lib/Socket/business.js +46 -33
  23. package/lib/Socket/chats.js +286 -170
  24. package/lib/Socket/community.js +215 -77
  25. package/lib/Socket/groups.js +77 -61
  26. package/lib/Socket/index.js +4 -4
  27. package/lib/Socket/messages-recv.js +629 -457
  28. package/lib/Socket/messages-send.js +645 -656
  29. package/lib/Socket/mex.js +61 -0
  30. package/lib/Socket/newsletter.js +166 -245
  31. package/lib/Socket/socket.js +396 -170
  32. package/lib/Store/index.js +27 -11
  33. package/lib/Store/make-cache-manager-store.js +14 -15
  34. package/lib/Store/make-in-memory-store.js +28 -24
  35. package/lib/Types/LabelAssociation.js +2 -2
  36. package/lib/Types/Message.js +6 -6
  37. package/lib/Types/MexUpdates.js +5 -5
  38. package/lib/Types/Newsletter.js +32 -25
  39. package/lib/Types/State.js +4 -4
  40. package/lib/Types/index.js +28 -12
  41. package/lib/Utils/auth-utils.js +212 -375
  42. package/lib/Utils/baileys-event-stream.js +68 -69
  43. package/lib/Utils/browser-utils.js +43 -0
  44. package/lib/Utils/business.js +63 -53
  45. package/lib/Utils/chat-utils.js +241 -106
  46. package/lib/Utils/crypto.js +25 -45
  47. package/lib/Utils/decode-wa-message.js +361 -311
  48. package/lib/Utils/event-buffer.js +97 -42
  49. package/lib/Utils/generics.js +90 -207
  50. package/lib/Utils/history.js +29 -27
  51. package/lib/Utils/index.js +28 -14
  52. package/lib/Utils/link-preview.js +24 -62
  53. package/lib/Utils/logger.js +5 -5
  54. package/lib/Utils/lt-hash.js +29 -23
  55. package/lib/Utils/make-mutex.js +26 -28
  56. package/lib/Utils/message-retry-manager.js +55 -7
  57. package/lib/Utils/messages-media.js +434 -247
  58. package/lib/Utils/messages.js +963 -917
  59. package/lib/Utils/noise-handler.js +60 -20
  60. package/lib/Utils/pre-key-manager.js +126 -0
  61. package/lib/Utils/process-message.js +216 -141
  62. package/lib/Utils/signal.js +75 -37
  63. package/lib/Utils/use-multi-file-auth-state.js +18 -22
  64. package/lib/Utils/validate-connection.js +96 -66
  65. package/lib/WABinary/constants.js +1268 -1268
  66. package/lib/WABinary/decode.js +62 -34
  67. package/lib/WABinary/encode.js +57 -36
  68. package/lib/WABinary/generic-utils.js +4 -4
  69. package/lib/WABinary/index.js +27 -11
  70. package/lib/WABinary/jid-utils.js +58 -11
  71. package/lib/WAM/constants.js +19064 -11563
  72. package/lib/WAM/encode.js +71 -14
  73. package/lib/WAM/index.js +27 -11
  74. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +20 -16
  75. package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -2
  76. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +7 -4
  77. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +2 -2
  78. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -2
  79. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -2
  80. package/lib/WAUSync/Protocols/index.js +27 -11
  81. package/lib/WAUSync/USyncQuery.js +51 -28
  82. package/lib/WAUSync/index.js +27 -11
  83. package/lib/index.js +60 -31
  84. package/package.json +12 -17
  85. package/WAProto/AICommon/AICommon.d.ts +0 -11702
  86. package/WAProto/Adv/Adv.d.ts +0 -643
  87. package/WAProto/BotMetadata/BotMetadata.d.ts +0 -5654
  88. package/WAProto/Cert/Cert.d.ts +0 -613
  89. package/WAProto/ChatLockSettings/ChatLockSettings.d.ts +0 -476
  90. package/WAProto/CompanionReg/CompanionReg.d.ts +0 -1361
  91. package/WAProto/DeviceCapabilities/DeviceCapabilities.d.ts +0 -577
  92. package/WAProto/E2E/E2E.d.ts +0 -41724
  93. package/WAProto/Ephemeral/Ephemeral.d.ts +0 -114
  94. package/WAProto/HistorySync/HistorySync.d.ts +0 -51700
  95. package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.d.ts +0 -229
  96. package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.d.ts +0 -583
  97. package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.d.ts +0 -42897
  98. package/WAProto/MmsRetry/MmsRetry.d.ts +0 -243
  99. package/WAProto/Protocol/Protocol.d.ts +0 -270
  100. package/WAProto/Reporting/Reporting.d.ts +0 -371
  101. package/WAProto/ServerSync/ServerSync.d.ts +0 -1285
  102. package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.d.ts +0 -1868
  103. package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.d.ts +0 -767
  104. package/WAProto/StatusAttributions/StatusAttributions.d.ts +0 -1027
  105. package/WAProto/SyncAction/SyncAction.d.ts +0 -11193
  106. package/WAProto/UserPassword/UserPassword.d.ts +0 -363
  107. package/WAProto/VnameCert/VnameCert.d.ts +0 -821
  108. package/WAProto/Wa6/Wa6.d.ts +0 -2128
  109. package/WAProto/Web/Web.d.ts +0 -46383
  110. package/WAProto/index.d.ts +0 -55
  111. package/lib/Defaults/index.d.ts +0 -77
  112. package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
  113. package/lib/Signal/Group/group-session-builder.d.ts +0 -17
  114. package/lib/Signal/Group/group_cipher.d.ts +0 -19
  115. package/lib/Signal/Group/index.d.ts +0 -11
  116. package/lib/Signal/Group/keyhelper.d.ts +0 -16
  117. package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
  118. package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
  119. package/lib/Signal/Group/sender-key-message.d.ts +0 -19
  120. package/lib/Signal/Group/sender-key-name.d.ts +0 -19
  121. package/lib/Signal/Group/sender-key-record.d.ts +0 -32
  122. package/lib/Signal/Group/sender-key-state.d.ts +0 -44
  123. package/lib/Signal/Group/sender-message-key.d.ts +0 -11
  124. package/lib/Signal/libsignal.d.ts +0 -8
  125. package/lib/Signal/lid-mapping.d.ts +0 -28
  126. package/lib/Socket/Client/index.d.ts +0 -2
  127. package/lib/Socket/Client/types.d.ts +0 -16
  128. package/lib/Socket/Client/websocket.d.ts +0 -13
  129. package/lib/Socket/business.d.ts +0 -187
  130. package/lib/Socket/chats.d.ts +0 -97
  131. package/lib/Socket/community.d.ts +0 -129
  132. package/lib/Socket/groups.d.ts +0 -129
  133. package/lib/Socket/index.d.ts +0 -191
  134. package/lib/Socket/messages-recv.d.ts +0 -174
  135. package/lib/Socket/messages-send.d.ts +0 -165
  136. package/lib/Socket/newsletter.d.ts +0 -145
  137. package/lib/Socket/socket.d.ts +0 -45
  138. package/lib/Socket/usync.d.ts +0 -37
  139. package/lib/Socket/usync.js +0 -83
  140. package/lib/Store/index.d.ts +0 -4
  141. package/lib/Store/make-cache-manager-store.d.ts +0 -14
  142. package/lib/Store/make-in-memory-store.d.ts +0 -123
  143. package/lib/Store/make-ordered-dictionary.d.ts +0 -12
  144. package/lib/Store/object-repository.d.ts +0 -10
  145. package/lib/Types/Auth.d.ts +0 -121
  146. package/lib/Types/Bussiness.d.ts +0 -28
  147. package/lib/Types/Call.d.ts +0 -14
  148. package/lib/Types/Chat.d.ts +0 -143
  149. package/lib/Types/Contact.d.ts +0 -23
  150. package/lib/Types/Events.d.ts +0 -226
  151. package/lib/Types/GroupMetadata.d.ts +0 -66
  152. package/lib/Types/Label.d.ts +0 -48
  153. package/lib/Types/LabelAssociation.d.ts +0 -35
  154. package/lib/Types/Message.d.ts +0 -484
  155. package/lib/Types/MexUpdates.d.ts +0 -9
  156. package/lib/Types/Newsletter.d.ts +0 -109
  157. package/lib/Types/Product.d.ts +0 -92
  158. package/lib/Types/Signal.d.ts +0 -98
  159. package/lib/Types/Socket.d.ts +0 -141
  160. package/lib/Types/State.d.ts +0 -41
  161. package/lib/Types/USync.d.ts +0 -26
  162. package/lib/Types/index.d.ts +0 -80
  163. package/lib/Utils/auth-utils.d.ts +0 -21
  164. package/lib/Utils/baileys-event-stream.d.ts +0 -18
  165. package/lib/Utils/business.d.ts +0 -29
  166. package/lib/Utils/chat-utils.d.ts +0 -82
  167. package/lib/Utils/crypto.d.ts +0 -56
  168. package/lib/Utils/decode-wa-message.d.ts +0 -53
  169. package/lib/Utils/event-buffer.d.ts +0 -39
  170. package/lib/Utils/generics.d.ts +0 -117
  171. package/lib/Utils/history.d.ts +0 -23
  172. package/lib/Utils/index.d.ts +0 -20
  173. package/lib/Utils/link-preview.d.ts +0 -23
  174. package/lib/Utils/logger.d.ts +0 -13
  175. package/lib/Utils/lt-hash.d.ts +0 -14
  176. package/lib/Utils/make-mutex.d.ts +0 -9
  177. package/lib/Utils/message-retry-manager.d.ts +0 -88
  178. package/lib/Utils/messages-media.d.ts +0 -135
  179. package/lib/Utils/messages.d.ts +0 -105
  180. package/lib/Utils/noise-handler.d.ts +0 -20
  181. package/lib/Utils/process-message.d.ts +0 -49
  182. package/lib/Utils/signal.d.ts +0 -42
  183. package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
  184. package/lib/Utils/use-mongo-file-auth-state.js +0 -84
  185. package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
  186. package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
  187. package/lib/Utils/use-single-file-auth-state.js +0 -80
  188. package/lib/Utils/validate-connection.d.ts +0 -13
  189. package/lib/WABinary/constants.d.ts +0 -30
  190. package/lib/WABinary/decode.d.ts +0 -9
  191. package/lib/WABinary/encode.d.ts +0 -3
  192. package/lib/WABinary/generic-utils.d.ts +0 -28
  193. package/lib/WABinary/index.d.ts +0 -5
  194. package/lib/WABinary/jid-utils.d.ts +0 -58
  195. package/lib/WABinary/types.d.ts +0 -22
  196. package/lib/WAM/BinaryInfo.d.ts +0 -16
  197. package/lib/WAM/constants.d.ts +0 -47
  198. package/lib/WAM/encode.d.ts +0 -3
  199. package/lib/WAM/index.d.ts +0 -3
  200. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +0 -28
  201. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
  202. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -26
  203. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -14
  204. package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +0 -10
  205. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -14
  206. package/lib/WAUSync/Protocols/index.d.ts +0 -6
  207. package/lib/WAUSync/USyncQuery.d.ts +0 -31
  208. package/lib/WAUSync/USyncUser.d.ts +0 -12
  209. package/lib/WAUSync/index.d.ts +0 -3
  210. package/lib/index.d.ts +0 -13
@@ -1,22 +1,42 @@
1
1
  "use strict"
2
2
 
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod }
5
- }
6
-
7
3
  Object.defineProperty(exports, "__esModule", { value: true })
8
4
 
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")
5
+ const { Boom } = require("@hapi/boom")
6
+ const { randomBytes } = require("crypto")
7
+ const { promises } = require("fs")
8
+ const { proto } = require("../../WAProto")
9
+ const {
10
+ URL_REGEX,
11
+ WA_DEFAULT_EPHEMERAL
12
+ } = require("../Defaults/constants")
13
+ const { MEDIA_KEYS } = require("../Defaults/media")
14
+ const {
15
+ WAProto,
16
+ WAMessageStatus
17
+ } = require("../Types")
18
+ const {
19
+ isJidGroup,
20
+ isJidNewsletter,
21
+ isJidStatusBroadcast,
22
+ jidNormalizedUser
23
+ } = require("../WABinary")
24
+ const { sha256 } = require("./crypto")
25
+ const {
26
+ generateMessageID,
27
+ getKeyAuthor,
28
+ unixTimestampSeconds
29
+ } = require("./generics")
30
+ const {
31
+ downloadContentFromMessage,
32
+ encryptedStream,
33
+ generateThumbnail,
34
+ getAudioDuration,
35
+ getAudioWaveform,
36
+ getRawMediaUploadData,
37
+ getStream,
38
+ toBuffer
39
+ } = require("./messages-media")
20
40
 
21
41
  const MIMETYPE_MAP = {
22
42
  image: 'image/jpeg',
@@ -28,11 +48,11 @@ const MIMETYPE_MAP = {
28
48
  }
29
49
 
30
50
  const MessageTypeProto = {
31
- 'image': Types_1.WAProto.Message.ImageMessage,
32
- 'video': Types_1.WAProto.Message.VideoMessage,
33
- 'audio': Types_1.WAProto.Message.AudioMessage,
34
- 'sticker': Types_1.WAProto.Message.StickerMessage,
35
- 'document': Types_1.WAProto.Message.DocumentMessage,
51
+ 'image': WAProto.Message.ImageMessage,
52
+ 'video': WAProto.Message.VideoMessage,
53
+ 'audio': WAProto.Message.AudioMessage,
54
+ 'sticker': WAProto.Message.StickerMessage,
55
+ 'document': WAProto.Message.DocumentMessage
36
56
  }
37
57
 
38
58
  /**
@@ -40,7 +60,7 @@ const MessageTypeProto = {
40
60
  * @param text eg. hello https://google.com
41
61
  * @returns the URL, eg. https://google.com
42
62
  */
43
- const extractUrlFromText = (text) => text.match(Defaults_1.URL_REGEX)?.[0]
63
+ const extractUrlFromText = (text) => text.match(URL_REGEX)?.[0]
44
64
 
45
65
  const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
46
66
  const url = extractUrlFromText(text)
@@ -76,66 +96,71 @@ const assertColor = async (color) => {
76
96
 
77
97
  const prepareWAMessageMedia = async (message, options) => {
78
98
  const logger = options.logger
99
+
79
100
  let mediaType
80
-
81
- for (const key of Defaults_1.MEDIA_KEYS) {
101
+
102
+ for (const key of MEDIA_KEYS) {
82
103
  if (key in message) {
83
104
  mediaType = key
84
105
  }
85
106
  }
86
-
107
+
87
108
  if (!mediaType) {
88
- throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
109
+ throw new Boom('Invalid media type', { statusCode: 400 })
89
110
  }
90
-
111
+
91
112
  const uploadData = {
92
113
  ...message,
93
114
  media: message[mediaType]
94
115
  }
95
-
116
+
96
117
  delete uploadData[mediaType]
97
-
118
+
98
119
  // check if cacheable + generate cache key
99
120
  const cacheableKey = typeof uploadData.media === 'object' &&
100
121
  'url' in uploadData.media &&
101
122
  !!uploadData.media.url &&
102
123
  !!options.mediaCache &&
103
124
  mediaType + ':' + uploadData.media.url.toString()
104
-
125
+
105
126
  if (mediaType === 'document' && !uploadData.fileName) {
106
127
  uploadData.fileName = 'file'
107
128
  }
108
-
129
+
109
130
  if (!uploadData.mimetype) {
110
131
  uploadData.mimetype = MIMETYPE_MAP[mediaType]
111
132
  }
112
-
133
+
113
134
  if (cacheableKey) {
114
135
  const mediaBuff = await options.mediaCache.get(cacheableKey)
136
+
115
137
  if (mediaBuff) {
116
138
  logger?.debug({ cacheableKey }, 'got media cache hit')
117
- const obj = Types_1.WAProto.Message.decode(mediaBuff)
139
+
140
+ const obj = proto.Message.decode(mediaBuff)
118
141
  const key = `${mediaType}Message`
142
+
119
143
  Object.assign(obj[key], { ...uploadData, media: undefined })
144
+
120
145
  return obj
121
146
  }
122
147
  }
123
-
124
- const isNewsletter = !!options.jid && WABinary_1.isJidNewsletter(options.jid)
125
-
148
+
149
+ const isNewsletter = !!options.jid && isJidNewsletter(options.jid)
150
+
126
151
  if (isNewsletter) {
127
152
  logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter')
128
- const { filePath, fileSha256, fileLength } = await messages_media_1.getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger)
129
- const fileSha256B64 = fileSha256.toString('base64')
153
+ const { filePath, fileSha256, fileLength } = await getRawMediaUploadData(uploadData.media, options.mediaTypeOverride || mediaType, logger)
154
+ const fileSha256B64 = fileSha256.toString('base64');
130
155
  const { mediaUrl, directPath } = await options.upload(filePath, {
131
156
  fileEncSha256B64: fileSha256B64,
132
157
  mediaType: mediaType,
133
158
  timeoutMs: options.mediaUploadTimeoutMs
134
159
  })
135
-
136
- await fs_1.promises.unlink(filePath)
137
-
138
- const obj = Types_1.WAProto.Message.fromObject({
160
+
161
+ await promises.unlink(filePath)
162
+
163
+ const obj = WAProto.Message.fromObject({
139
164
  // todo: add more support here
140
165
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
141
166
  url: mediaUrl,
@@ -146,34 +171,35 @@ const prepareWAMessageMedia = async (message, options) => {
146
171
  media: undefined
147
172
  })
148
173
  })
149
-
174
+
150
175
  if (uploadData.ptv) {
151
176
  obj.ptvMessage = obj.videoMessage
152
177
  delete obj.videoMessage
153
178
  }
154
-
179
+
180
+ if (obj.stickerMessage) {
181
+ obj.stickerMessage.stickerSentTs = Date.now()
182
+ }
183
+
155
184
  if (cacheableKey) {
156
185
  logger?.debug({ cacheableKey }, 'set cache');
157
- await options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish())
186
+ await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish())
158
187
  }
159
-
188
+
160
189
  return obj
161
190
  }
162
-
191
+
163
192
  const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined'
164
193
  const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined'
165
194
  const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true
166
195
  const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true
167
196
  const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation
168
-
169
- const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await messages_media_1.encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
197
+ const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await encryptedStream(uploadData.media, options.mediaTypeOverride || mediaType, {
170
198
  logger,
171
199
  saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
172
200
  opts: options.options
173
201
  })
174
-
175
202
  const fileEncSha256B64 = fileEncSha256.toString('base64')
176
-
177
203
  const [{ mediaUrl, directPath }] = await Promise.all([
178
204
  (async () => {
179
205
  const result = await options.upload(encFilePath, {
@@ -184,32 +210,31 @@ const prepareWAMessageMedia = async (message, options) => {
184
210
  logger?.debug({ mediaType, cacheableKey }, 'uploaded media')
185
211
  return result
186
212
  })(),
187
-
188
213
  (async () => {
189
214
  try {
190
215
  if (requiresThumbnailComputation) {
191
- const { thumbnail, originalImageDimensions } = await messages_media_1.generateThumbnail(originalFilePath, mediaType, options)
216
+ const { thumbnail, originalImageDimensions } = await generateThumbnail(originalFilePath, mediaType, options)
217
+
192
218
  uploadData.jpegThumbnail = thumbnail
219
+
193
220
  if (!uploadData.width && originalImageDimensions) {
194
221
  uploadData.width = originalImageDimensions.width
195
222
  uploadData.height = originalImageDimensions.height
196
-
197
223
  logger?.debug('set dimensions')
198
224
  }
199
-
200
- logger?.debug('generated thumbnail');
225
+ logger?.debug('generated thumbnail')
201
226
  }
202
-
227
+
203
228
  if (requiresDurationComputation) {
204
- uploadData.seconds = await messages_media_1.getAudioDuration(originalFilePath)
229
+ uploadData.seconds = await getAudioDuration(originalFilePath)
205
230
  logger?.debug('computed audio duration')
206
231
  }
207
-
232
+
208
233
  if (requiresWaveformProcessing) {
209
- uploadData.waveform = await messages_media_1.getAudioWaveform(originalFilePath, logger)
234
+ uploadData.waveform = await getAudioWaveform(originalFilePath, logger)
210
235
  logger?.debug('processed waveform')
211
236
  }
212
-
237
+
213
238
  if (requiresAudioBackground) {
214
239
  uploadData.backgroundArgb = await assertColor(options.backgroundColor)
215
240
  logger?.debug('computed backgroundColor audio status')
@@ -221,20 +246,20 @@ const prepareWAMessageMedia = async (message, options) => {
221
246
  })()
222
247
  ]).finally(async () => {
223
248
  try {
224
- await fs_1.promises.unlink(encFilePath)
225
-
249
+ await promises.unlink(encFilePath)
250
+
226
251
  if (originalFilePath) {
227
- await fs_1.promises.unlink(originalFilePath)
252
+ await promises.unlink(originalFilePath)
228
253
  }
229
-
254
+
230
255
  logger?.debug('removed tmp files')
231
256
  }
232
257
  catch (error) {
233
258
  logger?.warn('failed to remove tmp file')
234
259
  }
235
260
  })
236
-
237
- const obj = Types_1.WAProto.Message.fromObject({
261
+
262
+ const obj = WAProto.Message.fromObject({
238
263
  [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
239
264
  url: mediaUrl,
240
265
  directPath,
@@ -242,88 +267,99 @@ const prepareWAMessageMedia = async (message, options) => {
242
267
  fileEncSha256,
243
268
  fileSha256,
244
269
  fileLength,
245
- mediaKeyTimestamp: generics_1.unixTimestampSeconds(),
270
+ mediaKeyTimestamp: unixTimestampSeconds(),
246
271
  ...uploadData,
247
272
  media: undefined
248
273
  })
249
274
  })
250
-
275
+
251
276
  if (uploadData.ptv) {
252
277
  obj.ptvMessage = obj.videoMessage
253
278
  delete obj.videoMessage
254
279
  }
255
-
280
+
256
281
  if (cacheableKey) {
257
- logger?.debug({ cacheableKey }, 'set cache');
258
- await options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish())
282
+ logger?.debug({ cacheableKey }, 'set cache')
283
+ await options.mediaCache.set(cacheableKey, WAProto.Message.encode(obj).finish())
259
284
  }
260
-
285
+
261
286
  return obj
262
287
  }
263
288
 
264
289
  const prepareAlbumMessageContent = async (jid, albums, options) => {
265
- let mediaHandle
266
- let mediaMsg
267
- let message = []
268
-
269
- const albumMsg = generateWAMessageFromContent(jid, {
270
- albumMessage: {
271
- expectedImageCount: albums.filter(item => 'image' in item).length,
272
- expectedVideoCount: albums.filter(item => 'video' in item).length
273
- }
274
- }, options)
275
-
276
- await options.suki.relayMessage(jid, albumMsg.message, {
277
- messageId: albumMsg.key.id
278
- })
279
-
280
- for (const i in albums) {
281
- const media = albums[i]
282
-
283
- if ('image' in media) {
284
- mediaMsg = await generateWAMessage(jid, {
285
- image: media.image,
286
- ...media,
287
- ...options
288
- }, {
289
- userJid: options.userJid,
290
- upload: async (encFilePath, opts) => {
291
- const up = await options.suki.waUploadToServer(encFilePath, { ...opts, newsletter: WABinary_1.isJidNewsletter(jid) })
292
- mediaHandle = up.handle
293
- return up
294
- },
295
- ...options
296
- })
297
- } else if ('video' in message) {
298
- mediaMsg = await generateWAMessage(jid, {
299
- video: media.video,
300
- ...media,
301
- ...options
302
- }, {
303
- userJid: options.userJid,
304
- upload: async (encFilePath, opts) => {
305
- const up = await options.suki.waUploadToServer(encFilePath, { ...opts, newsletter: WABinary_1.isJidNewsletter(jid) })
306
- mediaHandle = up.handle
307
- return up
308
- },
309
- ...options
310
- })
311
- }
290
+ if (!Array.isArray(albums)) {
291
+ throw new Error("albums must be an array containing media objects.")
292
+ }
293
+
294
+ if (albums.length === 0) {
295
+ throw new Error("albums cannot be empty. At least one media item is required.")
296
+ }
297
+
298
+ const validCount = albums.filter(m => ('image' in m) || ('video' in m)).length
299
+
300
+ if (validCount === 0) {
301
+ throw new Error("albums contains no valid media. Use 'image' or 'video' keys.")
302
+ }
312
303
 
313
- if (mediaMsg) {
314
- mediaMsg.message.messageContextInfo = {
315
- messageSecret: crypto_1.randomBytes(32),
316
- messageAssociation: {
317
- associationType: 1,
318
- parentMessageKey: albumMsg.key
319
- }
320
- }
321
- }
304
+ let mediaHandle
305
+ let mediaMsg
306
+ const message = []
322
307
 
323
- message.push(mediaMsg)
308
+ const albumMsg = generateWAMessageFromContent(jid, {
309
+ albumMessage: {
310
+ expectedImageCount: albums.filter(item => 'image' in item).length,
311
+ expectedVideoCount: albums.filter(item => 'video' in item).length
324
312
  }
313
+ }, options)
325
314
 
326
- return message
315
+ await options.suki.relayMessage(jid, albumMsg.message, {
316
+ messageId: albumMsg.key.id
317
+ })
318
+
319
+ for (const media of albums) {
320
+ let content = {}
321
+ if ('image' in media) {
322
+ content = { image: media.image }
323
+ } else if ('video' in media) {
324
+ content = { video: media.video }
325
+ } else {
326
+ continue
327
+ }
328
+
329
+ mediaMsg = await generateWAMessage(
330
+ jid,
331
+ {
332
+ ...content,
333
+ ...media
334
+ },
335
+ {
336
+ userJid: options.userJid,
337
+ upload: async (encFilePath, opts) => {
338
+ const up = await options.suki.waUploadToServer(
339
+ encFilePath,
340
+ { ...opts, newsletter: isJidNewsletter(jid) }
341
+ )
342
+ mediaHandle = up.handle
343
+ return up
344
+ },
345
+ ...options
346
+ }
347
+ )
348
+
349
+ if (mediaMsg) {
350
+ mediaMsg.message.messageContextInfo = {
351
+ messageSecret: randomBytes(32),
352
+ messageAssociation: {
353
+ associationType: proto.MessageAssociation.AssociationType.MEDIA_ALBUM,
354
+ parentMessageKey: albumMsg.key
355
+ }
356
+ }
357
+ }
358
+
359
+ message.push(mediaMsg)
360
+ }
361
+
362
+ return message
327
363
  }
328
364
 
329
365
  const prepareDisappearingMessageSettingContent = (expiration) => {
@@ -331,14 +367,14 @@ const prepareDisappearingMessageSettingContent = (expiration) => {
331
367
  ephemeralMessage: {
332
368
  message: {
333
369
  protocolMessage: {
334
- type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
370
+ type: WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
335
371
  ephemeralExpiration: expiration ? expiration : 0
336
372
  }
337
373
  }
338
374
  }
339
375
  }
340
376
 
341
- return Types_1.WAProto.Message.fromObject(content)
377
+ return WAProto.Message.fromObject(content)
342
378
  }
343
379
 
344
380
  /**
@@ -350,12 +386,12 @@ const generateForwardMessageContent = (message, forceForward) => {
350
386
  let content = message.message
351
387
 
352
388
  if (!content) {
353
- throw new boom_1.Boom('no content in message', { statusCode: 400 })
389
+ throw new Boom('no content in message', { statusCode: 400 })
354
390
  }
355
391
 
356
392
  // hacky copy
357
393
  content = normalizeMessageContent(content)
358
- content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish())
394
+ content = proto.Message.decode(proto.Message.encode(content).finish())
359
395
 
360
396
  let key = Object.keys(content)[0]
361
397
  let score = content[key].contextInfo?.forwardingScore || 0
@@ -379,883 +415,920 @@ const generateForwardMessageContent = (message, forceForward) => {
379
415
  return content
380
416
  }
381
417
 
382
- const generateWAMessageContent = async (message, options) => {
383
- let m = {}
384
- if ('text' in message) {
385
- const extContent = { text: message.text }
386
- let urlInfo = message.linkPreview
387
-
388
- if (typeof urlInfo === 'undefined') {
389
- urlInfo = await generateLinkPreviewIfRequired(message.text, options.getUrlInfo, options.logger)
390
- }
391
-
392
- if (urlInfo) {
393
- extContent.canonicalUrl = urlInfo['canonical-url']
394
- extContent.matchedText = urlInfo['matched-text']
395
- extContent.jpegThumbnail = urlInfo.jpegThumbnail
396
- extContent.description = urlInfo.description
397
- extContent.title = urlInfo.title
398
- extContent.previewType = 0
399
- const img = urlInfo.highQualityThumbnail
400
-
401
- if (img) {
402
- extContent.thumbnailDirectPath = img.directPath
403
- extContent.mediaKey = img.mediaKey
404
- extContent.mediaKeyTimestamp = img.mediaKeyTimestamp
405
- extContent.thumbnailWidth = img.width
406
- extContent.thumbnailHeight = img.height
407
- extContent.thumbnailSha256 = img.fileSha256
408
- extContent.thumbnailEncSha256 = img.fileEncSha256
409
- }
410
- }
411
-
412
- if (options.backgroundColor) {
413
- extContent.backgroundArgb = await assertColor(options.backgroundColor)
414
- }
415
-
416
- if (options.textColor) {
417
- extContent.textArgb = await assertColor(options.textColor)
418
- }
418
+ const hasNonNullishProperty = (message, key) => {
419
+ return (
420
+ typeof message === 'object' &&
421
+ message !== null &&
422
+ key in message &&
423
+ message[key] !== null &&
424
+ message[key] !== undefined
425
+ )
426
+ }
419
427
 
420
- if (options.font) {
421
- extContent.font = options.font
422
- }
428
+ function hasOptionalProperty(obj, key) {
429
+ return (
430
+ typeof obj === 'object' &&
431
+ obj !== null &&
432
+ key in obj &&
433
+ obj[key] !== null
434
+ )
435
+ }
423
436
 
424
- extContent.contextInfo = {
425
- ...(message.contextInfo || {}),
426
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
427
- }
437
+ const generateWAMessageContent = async (message, options) => {
438
+ const hasMedia = [
439
+ "image",
440
+ "video",
441
+ "audio",
442
+ "sticker",
443
+ "document",
444
+ ].some((key) => hasNonNullishProperty(message, key))
428
445
 
429
- m.extendedTextMessage = extContent
430
- }
446
+ let m = {}
431
447
 
432
- else if ('contacts' in message) {
448
+ if (hasNonNullishProperty(message, "contacts")) {
433
449
  const contactLen = message.contacts.contacts.length
434
450
 
435
451
  let contactMessage
436
452
 
437
453
  if (!contactLen) {
438
- throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 })
454
+ throw new Boom("require atleast 1 contact", { statusCode: 400 })
439
455
  }
440
456
 
441
457
  if (contactLen === 1) {
442
458
  contactMessage = {
443
- contactMessage: Types_1.WAProto.Message.ContactMessage.fromObject(message.contacts.contacts[0])
459
+ contactMessage: WAProto.Message.ContactMessage.fromObject(
460
+ message.contacts.contacts[0]
461
+ ),
444
462
  }
445
- }
446
-
447
- else {
463
+ } else {
448
464
  contactMessage = {
449
- contactsArrayMessage: Types_1.WAProto.Message.ContactsArrayMessage.fromObject(message.contacts)
465
+ contactsArrayMessage: WAProto.Message.ContactsArrayMessage.fromObject(
466
+ message.contacts
467
+ ),
450
468
  }
451
469
  }
452
470
 
453
- const [type] = Object.keys(contactMessage)
454
-
455
- contactMessage[type].contextInfo = {
456
- ...(message.contextInfo || {}),
457
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
458
- }
459
-
460
471
  m = contactMessage
461
- }
472
+ } else if (hasNonNullishProperty(message, "contacts")) {
473
+ const contactLen = message.contacts.contacts.length
462
474
 
463
- else if ('location' in message) {
464
- let locationMessage
475
+ let contactMessage
465
476
 
466
- if (message.live) {
467
- locationMessage = {
468
- liveLocationMessage: Types_1.WAProto.Message.LiveLocationMessage.fromObject(message.location)
469
- }
477
+ if (!contactLen) {
478
+ throw new Boom("require atleast 1 contact", { statusCode: 400 })
470
479
  }
471
480
 
472
- else {
473
- locationMessage = {
474
- locationMessage: Types_1.WAProto.Message.LocationMessage.fromObject(message.location)
481
+ if (contactLen === 1) {
482
+ contactMessage = {
483
+ contactMessage: WAProto.Message.ContactMessage.fromObject(
484
+ message.contacts.contacts[0]
485
+ ),
486
+ }
487
+ } else {
488
+ contactMessage = {
489
+ contactsArrayMessage: WAProto.Message.ContactsArrayMessage.fromObject(
490
+ message.contacts
491
+ ),
475
492
  }
476
493
  }
477
494
 
478
- const [type] = Object.keys(locationMessage)
479
-
480
- locationMessage[type].contextInfo = {
481
- ...(message.contextInfo || {}),
482
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
495
+ m = contactMessage
496
+ } else if (hasNonNullishProperty(message, "location")) {
497
+ let locationMessage
498
+
499
+ if (message.live) {
500
+ locationMessage = {
501
+ liveLocationMessage: WAProto.Message.LiveLocationMessage.fromObject(
502
+ message.location
503
+ ),
504
+ }
505
+ } else {
506
+ locationMessage = {
507
+ locationMessage: WAProto.Message.LocationMessage.fromObject(
508
+ message.location
509
+ ),
510
+ }
483
511
  }
484
512
 
485
513
  m = locationMessage
486
- }
487
-
488
- else if ('react' in message) {
514
+ } else if (hasNonNullishProperty(message, "react")) {
489
515
  if (!message.react.senderTimestampMs) {
490
516
  message.react.senderTimestampMs = Date.now()
491
517
  }
492
518
 
493
- m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react)
494
- }
495
-
496
- else if ('delete' in message) {
519
+ m.reactionMessage = WAProto.Message.ReactionMessage.fromObject(
520
+ message.react
521
+ )
522
+ } else if (hasNonNullishProperty(message, "delete")) {
497
523
  m.protocolMessage = {
498
524
  key: message.delete,
499
- type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
525
+ type: WAProto.Message.ProtocolMessage.Type.REVOKE,
500
526
  }
501
- }
502
-
503
- else if ('forward' in message) {
504
- const mess = generateForwardMessageContent(message.forward, message.force)
505
- const [type] = Object.keys(mess)
506
-
507
- mess[type].contextInfo = {
508
- ...(message.contextInfo || {}),
509
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
527
+ } else if (hasNonNullishProperty(message, "sharePhoneNumber")) {
528
+ m.protocolMessage = {
529
+ type: WAProto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER,
510
530
  }
511
-
512
- m = mess
513
- }
514
-
515
- else if ('disappearingMessagesInChat' in message) {
516
- const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
517
- (message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
518
- message.disappearingMessagesInChat
531
+ } else if (hasNonNullishProperty(message, "requestPhoneNumber")) {
532
+ m.requestPhoneNumberMessage = {}
533
+ } else if (hasNonNullishProperty(message, "forward")) {
534
+ m = generateForwardMessageContent(message.forward, message.force)
535
+ } else if (hasNonNullishProperty(message, "disappearingMessagesInChat")) {
536
+ const exp =
537
+ typeof message.disappearingMessagesInChat === "boolean"
538
+ ? message.disappearingMessagesInChat
539
+ ? WA_DEFAULT_EPHEMERAL
540
+ : 0
541
+ : message.disappearingMessagesInChat
519
542
  m = prepareDisappearingMessageSettingContent(exp)
520
- }
521
-
522
- else if ('groupInvite' in message) {
523
- m.groupInviteMessage = {}
543
+ } else if (hasNonNullishProperty(message, "groupInvite")) {
544
+ m.groupInviteMessage = {}
524
545
 
525
546
  m.groupInviteMessage.inviteCode = message.groupInvite.code
526
547
  m.groupInviteMessage.inviteExpiration = message.groupInvite.expiration
527
548
  m.groupInviteMessage.caption = message.groupInvite.caption
528
549
  m.groupInviteMessage.groupJid = message.groupInvite.jid
529
- m.groupInviteMessage.groupName = message.groupInvite.name
530
- m.groupInviteMessage.contextInfo = message.contextInfo
550
+ m.groupInviteMessage.groupName = message.groupInvite.name
551
+ m.groupInviteMessage.contextInfo = message.contextInfo
531
552
 
532
553
  if (options.getProfilePicUrl) {
533
- const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid)
534
- const { thumbnail } = await messages_media_1.generateThumbnail(pfpUrl, 'image')
554
+ const pfpUrl = await options.getProfilePicUrl(
555
+ message.groupInvite.jid
556
+ )
557
+ const { thumbnail } = await generateThumbnail(pfpUrl, "image")
535
558
  m.groupInviteMessage.jpegThumbnail = thumbnail
536
559
  }
537
-
538
- m.groupInviteMessage.contextInfo = {
539
- ...(message.contextInfo || {}),
540
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
541
- }
542
- }
543
-
544
- else if ('adminInvite' in message) {
545
- m.newsletterAdminInviteMessage = {}
560
+ } else if (hasNonNullishProperty(message, "adminInvite")) {
561
+ m.newsletterAdminInviteMessage = {}
546
562
 
547
563
  m.newsletterAdminInviteMessage.newsletterJid = message.adminInvite.jid
548
- m.newsletterAdminInviteMessage.newsletterName= message.adminInvite.name
564
+ m.newsletterAdminInviteMessage.newsletterName =
565
+ message.adminInvite.name
549
566
  m.newsletterAdminInviteMessage.caption = message.adminInvite.caption
550
- m.newsletterAdminInviteMessage.inviteExpiration = message.adminInvite.expiration
551
- m.newsletterAdminInviteMessage.contextInfo = message.contextInfo
567
+ m.newsletterAdminInviteMessage.inviteExpiration =
568
+ message.adminInvite.expiration
569
+ m.newsletterAdminInviteMessage.contextInfo = message.contextInfo
552
570
 
553
571
  if (options.getProfilePicUrl) {
554
- const pfpUrl = await options.getProfilePicUrl(message.adminInvite.jid)
555
- const { thumbnail } = await messages_media_1.generateThumbnail(pfpUrl, 'image')
572
+ const pfpUrl = await options.getProfilePicUrl(
573
+ message.adminInvite.jid
574
+ )
575
+ const { thumbnail } = await generateThumbnail(pfpUrl, "image")
556
576
  m.newsletterAdminInviteMessage.jpegThumbnail = thumbnail
557
577
  }
558
-
559
- m.newsletterAdminInviteMessage.contextInfo = {
560
- ...(message.contextInfo || {}),
561
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
562
- }
563
- }
564
-
565
- else if ('pin' in message) {
566
- m.pinInChatMessage = {}
567
- m.messageContextInfo = {}
568
-
569
- m.pinInChatMessage.key = message.pin.key
570
- m.pinInChatMessage.type = message.pin?.type || 1
571
- m.pinInChatMessage.senderTimestampMs = message.pin?.time || Date.now()
572
- m.messageContextInfo.messageAddOnDurationInSecs = message.pin.type === 1 ? message.pin.time || 86400 : 0
573
- m.messageContextInfo.messageAddOnExpiryType = WAProto_1.proto.MessageContextInfo.MessageAddonExpiryType.STATIC
574
- }
575
-
576
- else if ('keep' in message) {
578
+ } else if (hasNonNullishProperty(message, "keep")) {
577
579
  m.keepInChatMessage = {}
578
580
 
579
581
  m.keepInChatMessage.key = message.keep.key
580
582
  m.keepInChatMessage.keepType = message.keep?.type || 1
581
583
  m.keepInChatMessage.timestampMs = message.keep?.time || Date.now()
582
- }
583
-
584
- else if ('call' in message) {
584
+ } else if (hasNonNullishProperty(message, "call")) {
585
585
  m.scheduledCallCreationMessage = {}
586
586
 
587
- m.scheduledCallCreationMessage.scheduledTimestampMs = message.call?.time || Date.now()
587
+ m.scheduledCallCreationMessage.scheduledTimestampMs =
588
+ message.call?.time || Date.now()
588
589
  m.scheduledCallCreationMessage.callType = message.call?.type || 1
589
- m.scheduledCallCreationMessage.title = message.call?.name || 'Call Creation'
590
+ m.scheduledCallCreationMessage.title =
591
+ message.call?.name || "Call Creation"
592
+ } else if (hasNonNullishProperty(message, "paymentInvite")) {
593
+ m.messageContextInfo = {}
594
+ m.paymentInviteMessage = {}
595
+
596
+ m.paymentInviteMessage.expiryTimestamp =
597
+ message.paymentInvite?.expiry || 0
598
+ m.paymentInviteMessage.serviceType = message.paymentInvite?.type || 2
599
+ } else if (hasNonNullishProperty(message, "ptv")) {
600
+ const { videoMessage } = await prepareWAMessageMedia(
601
+ { video: message.video },
602
+ options
603
+ )
604
+
605
+ m.ptvMessage = videoMessage
606
+ } else if (hasNonNullishProperty(message, "order")) {
607
+ m.orderMessage = WAProto.Message.OrderMessage.fromObject(message.order)
608
+ } else if (hasNonNullishProperty(message, "product")) {
609
+ const { imageMessage } = await prepareWAMessageMedia(
610
+ { image: message.product.productImage },
611
+ options
612
+ )
613
+
614
+ m.productMessage = WAProto.Message.ProductMessage.fromObject({
615
+ ...message,
616
+ product: {
617
+ ...message.product,
618
+ productImage: imageMessage,
619
+ },
620
+ })
621
+ } else if (hasNonNullishProperty(message, "album")) {
622
+ const imageMessages = message.album.filter((item) => "image" in item)
623
+ const videoMessages = message.album.filter((item) => "video" in item)
590
624
 
591
- m.scheduledCallCreationMessage.contextInfo = {
592
- ...(message.contextInfo || {}),
593
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
625
+ m.albumMessage = WAProto.Message.AlbumMessage.fromObject({
626
+ expectedImageCount: imageMessages.length,
627
+ expectedVideoCount: videoMessages.length,
628
+ })
629
+ } else if (hasNonNullishProperty(message, "event")) {
630
+ m.eventMessage = WAProto.Message.EventMessage.fromObject(message.event)
631
+
632
+ if (!message.event.startTime) {
633
+ m.eventMessage.startTime = unixTimestampSeconds() + 86400
594
634
  }
595
- }
596
635
 
597
- else if ('paymentInvite' in message) {
598
- m.messageContextInfo = {}
599
- m.paymentInviteMessage = {}
636
+ if (options.getCallLink && message.event.call) {
637
+ const link = await options.getCallLink(
638
+ message.event.call,
639
+ m.eventMessage.startTime
640
+ )
641
+ m.eventMessage.joinLink = link
642
+ }
643
+ } else if (hasNonNullishProperty(message, "pollResult")) {
644
+ if (!Array.isArray(message.pollResult.values)) {
645
+ throw new Boom("Invalid pollResult values", { statusCode: 400 })
646
+ }
600
647
 
601
- m.paymentInviteMessage.expiryTimestamp = message.paymentInvite?.expiry || 0
602
- m.paymentInviteMessage.serviceType = message.paymentInvite?.type || 2
648
+ const pollResultSnapshotMessage = {
649
+ name: message.pollResult.name,
650
+ pollVotes: message.pollResult.values.map(
651
+ ([optionName, optionVoteCount]) => ({
652
+ optionName,
653
+ optionVoteCount,
654
+ })
655
+ ),
656
+ }
657
+
658
+ m.pollResultSnapshotMessage = pollResultSnapshotMessage
659
+ } else if (hasNonNullishProperty(message, "poll")) {
660
+ if (!Array.isArray(message.poll.values)) {
661
+ throw new Boom("Invalid poll values", { statusCode: 400 })
662
+ }
663
+
664
+ if (
665
+ message.poll.selectableCount < 0 ||
666
+ message.poll.selectableCount > message.poll.values.length
667
+ ) {
668
+ throw new Boom(
669
+ `poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`,
670
+ { statusCode: 400 }
671
+ )
672
+ }
603
673
 
604
- m.paymentInviteMessage.contextInfo = {
605
- ...(message.contextInfo || {}),
606
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
674
+ const pollCreationMessage = {
675
+ name: message.poll.name,
676
+ selectableOptionsCount: message.poll?.selectableCount || 0,
677
+ options: message.poll.values.map((optionName) => ({ optionName })),
678
+ }
679
+
680
+ if (message.poll?.toAnnouncementGroup) {
681
+ m.pollCreationMessageV2 = pollCreationMessage
682
+ } else {
683
+ if (message.poll.selectableCount > 0) {
684
+ m.pollCreationMessageV3 = pollCreationMessage
685
+ } else {
686
+ m.pollCreationMessage = pollCreationMessage
687
+ }
607
688
  }
608
- }
689
+ } else if (hasNonNullishProperty(message, "payment")) {
690
+ const requestPaymentMessage = {
691
+ amount: {
692
+ currencyCode: message.payment?.currency || "IDR",
693
+ offset: message.payment?.offset || 0,
694
+ value: message.payment?.amount || 999999999,
695
+ },
696
+ expiryTimestamp: message.payment?.expiry || 0,
697
+ amount1000: message.payment?.amount || 999999999 * 1000,
698
+ currencyCodeIso4217: message.payment?.currency || "IDR",
699
+ requestFrom: message.payment?.from || "0@s.whatsapp.net",
700
+ noteMessage: {
701
+ extendedTextMessage: {
702
+ text: message.payment?.note || "Notes",
703
+ },
704
+ },
705
+ background: {
706
+ placeholderArgb:
707
+ message.payment?.image?.placeholderArgb || 4278190080,
708
+ textArgb: message.payment?.image?.textArgb || 4294967295,
709
+ subtextArgb: message.payment?.image?.subtextArgb || 4294967295,
710
+ type: 1,
711
+ },
712
+ }
713
+
714
+ m.requestPaymentMessage = requestPaymentMessage
715
+ } else if (hasNonNullishProperty(message, "stickerPack")) {
716
+ const {
717
+ stickers,
718
+ cover,
719
+ name,
720
+ publisher,
721
+ packId,
722
+ description,
723
+ } = message.stickerPack
724
+
725
+ const { zip } = require("fflate")
726
+
727
+ const stickerData = {}
728
+ const stickerPromises = stickers.map(async (s, i) => {
729
+ const { stream } = await getStream(s.sticker)
730
+ const buffer = await toBuffer(stream)
731
+ const hash = sha256(buffer).toString("base64url")
732
+ const fileName = `${i.toString().padStart(2, "0")}_${hash}.webp`
733
+
734
+ stickerData[fileName] = [new Uint8Array(buffer), { level: 0 }]
735
+
736
+ return {
737
+ fileName,
738
+ mimetype: "image/webp",
739
+ isAnimated: s.isAnimated || false,
740
+ isLottie: s.isLottie || false,
741
+ emojis: s.emojis || [],
742
+ accessibilityLabel: s.accessibilityLabel || "",
743
+ }
744
+ })
745
+
746
+ const stickerMetadata = await Promise.all(stickerPromises)
747
+
748
+ const zipBuffer = await new Promise((resolve, reject) => {
749
+ zip(stickerData, (err, data) => {
750
+ if (err) {
751
+ reject(err)
752
+ } else {
753
+ resolve(Buffer.from(data))
754
+ }
755
+ })
756
+ })
609
757
 
610
- else if ('buttonReply' in message) {
758
+ const coverBuffer = await toBuffer((await getStream(cover)).stream)
759
+
760
+ const [stickerPackUpload, coverUpload] = await Promise.all([
761
+ encryptedStream(zipBuffer, "sticker-pack", {
762
+ logger: options.logger,
763
+ opts: options.options,
764
+ }),
765
+ prepareWAMessageMedia(
766
+ { image: coverBuffer },
767
+ { ...options, mediaTypeOverride: "image" }
768
+ ),
769
+ ])
770
+
771
+ const stickerPackUploadResult = await options.upload(
772
+ stickerPackUpload.encFilePath,
773
+ {
774
+ fileEncSha256B64: stickerPackUpload.fileEncSha256.toString(
775
+ "base64"
776
+ ),
777
+ mediaType: "sticker-pack",
778
+ timeoutMs: options.mediaUploadTimeoutMs,
779
+ }
780
+ )
781
+
782
+ const coverImage = coverUpload.imageMessage
783
+ const imageDataHash = sha256(coverBuffer).toString("base64")
784
+ const stickerPackId = packId || generateMessageID()
785
+
786
+ m.stickerPackMessage = {
787
+ name,
788
+ publisher,
789
+ stickerPackId,
790
+ packDescription: description,
791
+ stickerPackOrigin:
792
+ proto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
793
+ stickerPackSize: stickerPackUpload.fileLength,
794
+ stickers: stickerMetadata,
795
+ fileSha256: stickerPackUpload.fileSha256,
796
+ fileEncSha256: stickerPackUpload.fileEncSha256,
797
+ mediaKey: stickerPackUpload.mediaKey,
798
+ directPath: stickerPackUploadResult.directPath,
799
+ fileLength: stickerPackUpload.fileLength,
800
+ mediaKeyTimestamp: unixTimestampSeconds(),
801
+ trayIconFileName: `${stickerPackId}.png`,
802
+ imageDataHash,
803
+ thumbnailDirectPath: coverImage.directPath,
804
+ thumbnailFileSha256: coverImage.fileSha256,
805
+ thumbnailFileEncSha256: coverImage.fileEncSha256,
806
+ thumbnailHeight: coverImage.height,
807
+ thumbnailWidth: coverImage.width,
808
+ }
809
+ } else if (hasNonNullishProperty(message, "buttonReply")) {
611
810
  switch (message.type) {
612
- case 'list':
811
+ case "list":
613
812
  m.listResponseMessage = {
614
813
  title: message.buttonReply.title,
615
814
  description: message.buttonReply.description,
616
815
  singleSelectReply: {
617
- selectedRowId: message.buttonReply.rowId
618
- },
619
- lisType: WAProto_1.proto.Message.ListResponseMessage.ListType.SINGLE_SELECT
816
+ selectedRowId: message.buttonReply.rowId,
817
+ },
818
+ lisType:
819
+ proto.Message.ListResponseMessage.ListType
820
+ .SINGLE_SELECT,
620
821
  }
621
822
  break
622
- case 'template':
823
+ case "template":
623
824
  m.templateButtonReplyMessage = {
624
825
  selectedDisplayText: message.buttonReply.displayText,
625
826
  selectedId: message.buttonReply.id,
626
- selectedIndex: message.buttonReply.index
827
+ selectedIndex: message.buttonReply.index,
627
828
  }
628
829
  break
629
- case 'plain':
830
+ case "plain":
630
831
  m.buttonsResponseMessage = {
631
832
  selectedButtonId: message.buttonReply.id,
632
833
  selectedDisplayText: message.buttonReply.displayText,
633
- type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
834
+ type:
835
+ proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
634
836
  }
635
837
  break
636
- case 'interactive':
838
+ case "interactive":
637
839
  m.interactiveResponseMessage = {
638
840
  body: {
639
- text: message.buttonReply.displayText,
640
- format: WAProto_1.proto.Message.InteractiveResponseMessage.Body.Format.EXTENSIONS_1
641
- },
841
+ text: message.buttonReply.displayText,
842
+ format:
843
+ proto.Message.InteractiveResponseMessage.Body.Format
844
+ .EXTENSIONS_1,
845
+ },
642
846
  nativeFlowResponseMessage: {
643
- name: message.buttonReply.nativeFlows.name,
644
- paramsJson: message.buttonReply.nativeFlows.paramsJson,
645
- version: message.buttonReply.nativeFlows.version
646
- }
847
+ name: message.buttonReply.nativeFlows.name,
848
+ paramsJson: message.buttonReply.nativeFlows.paramsJson,
849
+ version: message.buttonReply.nativeFlows.version,
850
+ },
647
851
  }
648
- break
852
+ break
853
+ }
854
+ } else if (hasNonNullishProperty(message, "sections")) {
855
+ m.listMessage = {
856
+ title: message.title,
857
+ buttonText: message.buttonText,
858
+ footerText: message.footer,
859
+ description: message.text,
860
+ sections: message.sections,
861
+ listType: proto.Message.ListMessage.ListType.SINGLE_SELECT,
862
+ }
863
+ } else if (hasNonNullishProperty(message, "productList")) {
864
+ const thumbnail = message.thumbnail
865
+ ? await generateThumbnail(message.thumbnail, "image")
866
+ : null
867
+
868
+ m.listMessage = {
869
+ title: message.title,
870
+ buttonText: message.buttonText,
871
+ footerText: message.footer,
872
+ description: message.text,
873
+ productListInfo: {
874
+ productSections: message.productList,
875
+ headerImage: {
876
+ productId: message.productList[0].products[0].productId,
877
+ jpegThumbnail: thumbnail?.thumbnail || null,
878
+ },
879
+ businessOwnerJid: message.businessOwnerJid,
880
+ },
881
+ listType: proto.Message.ListMessage.ListType.PRODUCT_LIST,
882
+ }
883
+ } else if (hasNonNullishProperty(message, "buttons")) {
884
+ const buttonsMessage = {
885
+ buttons: message.buttons.map((b) => ({
886
+ ...b,
887
+ type: proto.Message.ButtonsMessage.Button.Type.RESPONSE,
888
+ })),
649
889
  }
650
- }
651
-
652
- else if ('ptv' in message && message.ptv) {
653
- const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options)
654
-
655
- m.ptvMessage = videoMessage
656
- }
657
890
 
658
- else if ('album' in message) {
659
- const imageMessages = message.album.filter(item => 'image' in item)
660
- const videoMessages = message.album.filter(item => 'video' in item)
891
+ if (hasNonNullishProperty(message, "text")) {
892
+ buttonsMessage.contentText = message.text
893
+ buttonsMessage.headerType =
894
+ proto.Message.ButtonsMessage.HeaderType.EMPTY
895
+ } else {
896
+ if (hasNonNullishProperty(message, "caption")) {
897
+ buttonsMessage.contentText = message.caption
898
+ }
661
899
 
662
- m.albumMessage = Types_1.WAProto.Message.AlbumMessage.fromObject({
663
- expectedImageCount: imageMessages.length,
664
- expectedVideoCount: videoMessages.length
665
- })
666
- }
900
+ const type = Object.keys(m)[0].replace("Message", "").toUpperCase()
667
901
 
668
- else if ('order' in message) {
669
- m.orderMessage = Types_1.WAProto.Message.OrderMessage.fromObject(message.order)
902
+ buttonsMessage.headerType =
903
+ proto.Message.ButtonsMessage.HeaderType[type]
670
904
 
671
- m.orderMessage.contextInfo = {
672
- ...(message.contextInfo || {}),
673
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
905
+ Object.assign(buttonsMessage, m)
674
906
  }
675
- }
676
-
677
- else if ('event' in message) {
678
- m.eventMessage = Types_1.WAProto.Message.EventMessage.fromObject(message.event)
679
-
680
- if (!message.event.startTime) {
681
- m.eventMessage.startTime = generics_1.unixTimestampSeconds() + 86400
682
- }
683
-
684
- if (options.getCallLink && message.event.call) {
685
- const link = await options.getCallLink(message.event.call, m.eventMessage.startTime)
686
- m.eventMessage.joinLink = link
687
- }
688
907
 
908
+ if (hasNonNullishProperty(message, "title")) {
909
+ buttonsMessage.text = message.title
910
+ buttonsMessage.headerType =
911
+ proto.Message.ButtonsMessage.HeaderType.TEXT
912
+ }
689
913
 
690
- m.eventMessage.contextInfo = {
691
- ...(message.contextInfo || {}),
692
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
914
+ if (hasNonNullishProperty(message, "footer")) {
915
+ buttonsMessage.footerText = message.footer
693
916
  }
694
- }
695
917
 
696
- else if ('product' in message) {
697
- const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options)
918
+ m = { buttonsMessage }
919
+ } else if (hasNonNullishProperty(message, "templateButtons")) {
920
+ const hydratedTemplate = {
921
+ hydratedButtons: message.templateButtons,
922
+ }
698
923
 
699
- m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
700
- ...message,
701
- product: {
702
- ...message.product,
703
- productImage: imageMessage,
924
+ if (hasNonNullishProperty(message, "text")) {
925
+ hydratedTemplate.hydratedContentText = message.text
926
+ } else {
927
+ if (hasNonNullishProperty(message, "caption")) {
928
+ hydratedTemplate.hydratedContentText = message.caption
704
929
  }
705
- })
706
930
 
707
- m.productMessage.contextInfo = {
708
- ...(message.contextInfo || {}),
709
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
931
+ Object.assign(msg, m)
710
932
  }
711
- }
712
933
 
713
- else if ('pollResult' in message) {
714
- if (!Array.isArray(message.pollResult.values)) {
715
- throw new boom_1.Boom('Invalid pollResult values', { statusCode: 400 })
934
+ if (hasNonNullishProperty(message, "footer")) {
935
+ hydratedTemplate.hydratedFooterText = message.footer
716
936
  }
717
937
 
718
- const pollResultSnapshotMessage = {
719
- name: message.pollResult.name,
720
- pollVotes: message.pollResult.values.map(([optionName, optionVoteCount]) => ({
721
- optionName,
722
- optionVoteCount
723
- }))
724
- }
725
-
726
- pollResultSnapshotMessage.contextInfo = {
727
- ...(message.contextInfo || {}),
728
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
938
+ m = { templateMessage: { hydratedTemplate } }
939
+ } else if (hasNonNullishProperty(message, "interactiveButtons")) {
940
+ const interactiveMessage = {
941
+ nativeFlowMessage: {
942
+ buttons: message.interactiveButtons,
943
+ },
729
944
  }
730
945
 
731
- m.pollResultSnapshotMessage = pollResultSnapshotMessage
732
- }
733
-
734
- else if ('poll' in message) {
735
- if (!Array.isArray(message.poll.values)) {
736
- throw new boom_1.Boom('Invalid poll values', { statusCode: 400 })
946
+ if (hasNonNullishProperty(message, "text")) {
947
+ interactiveMessage.body = {
948
+ text: message.text,
949
+ }
737
950
  }
738
951
 
739
- if (message.poll.selectableCount < 0
740
- || message.poll.selectableCount > message.poll.values.length) {
741
- throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, { statusCode: 400 })
742
- }
952
+ if (hasNonNullishProperty(message, "title")) {
953
+ interactiveMessage.header = {
954
+ title: message.title,
955
+ subtitle: null,
956
+ hasMediaAttachment: false,
957
+ }
743
958
 
744
- const pollCreationMessage = {
745
- name: message.poll.name,
746
- selectableOptionsCount: message.poll?.selectableCount || 0,
747
- options: message.poll.values.map(optionName => ({ optionName })),
748
- }
959
+ if (hasNonNullishProperty(message, "subtitle")) {
960
+ interactiveMessage.header.subtitle = message.subtitle
961
+ }
962
+ } else {
963
+ if (hasNonNullishProperty(message, "caption")) {
964
+ interactiveMessage.body = {
965
+ text: message.caption,
966
+ }
749
967
 
750
- pollCreationMessage.contextInfo = {
751
- ...(message.contextInfo || {}),
752
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
753
- }
968
+ interactiveMessage.header = {
969
+ title: null,
970
+ subtitle: null,
971
+ hasMediaAttachment: false,
972
+ ...Object.assign(interactiveMessage, m),
973
+ }
754
974
 
755
- if(message.poll?.toAnnouncementGroup) {
756
- m.pollCreationMessageV2 = pollCreationMessage
757
- } else {
758
- if(message.poll.selectableCount > 0) {
759
- m.pollCreationMessageV3 = pollCreationMessage
760
- } else {
761
- m.pollCreationMessage = pollCreationMessage
762
- }
975
+ if (hasNonNullishProperty(message, "title")) {
976
+ interactiveMessage.header.title = message.title
763
977
  }
764
- }
765
-
766
- else if ('payment' in message) {
767
- const requestPaymentMessage = {
768
- amount: {
769
- currencyCode: message.payment?.currency || 'IDR',
770
- offset: message.payment?.offset || 0,
771
- value: message.payment?.amount || 999999999
772
- },
773
- expiryTimestamp: message.payment?.expiry || 0,
774
- amount1000: message.payment?.amount || 999999999 * 1000,
775
- currencyCodeIso4217: message.payment?.currency || 'IDR',
776
- requestFrom: message.payment?.from || '0@s.whatsapp.net',
777
- noteMessage: {
778
- extendedTextMessage: {
779
- text: message.payment?.note || 'Notes'
780
- }
781
- },
782
- background: {
783
- placeholderArgb: message.payment?.image?.placeholderArgb || 4278190080,
784
- textArgb: message.payment?.image?.textArgb || 4294967295,
785
- subtextArgb: message.payment?.image?.subtextArgb || 4294967295,
786
- type: 1
787
- }
788
- }
789
978
 
790
- requestPaymentMessage.noteMessage.extendedTextMessage.contextInfo = {
791
- ...(message.contextInfo || {}),
792
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
793
- }
979
+ if (hasNonNullishProperty(message, "subtitle")) {
980
+ interactiveMessage.header.subtitle = message.subtitle
981
+ }
794
982
 
795
- m.requestPaymentMessage = requestPaymentMessage
796
- }
797
-
798
- else if ('stickerPack' in message) {
799
- const { stickers, cover, name, publisher, packId, description } = message.stickerPack
800
-
801
- const { zip } = require('fflate')
802
-
803
- const stickerData = {}
804
- const stickerPromises = stickers.map(async (s, i) => {
805
- const { stream } = await messages_media_1.getStream(s.sticker)
806
- const buffer = await messages_media_1.toBuffer(stream)
807
- const hash = crypto_2.sha256(buffer).toString('base64url')
808
- const fileName = `${i.toString().padStart(2, '0')}_${hash}.webp`
809
- stickerData[fileName] = [new Uint8Array(buffer), { level: 0 }]
810
-
811
- return {
812
- fileName,
813
- mimetype: 'image/webp',
814
- isAnimated: s.isAnimated || false,
815
- isLottie: s.isLottie || false,
816
- emojis: s.emojis || [],
817
- accessibilityLabel: s.accessibilityLabel || ''
818
- }
819
- })
820
-
821
- const stickerMetadata = await Promise.all(stickerPromises)
822
-
823
- const zipBuffer = await new Promise((resolve, reject) => {
824
- zip(stickerData, (err, data) => {
825
- if (err) {
826
- reject(err)
827
- } else {
828
- resolve(Buffer.from(data))
829
- }
830
- })
831
- })
832
-
833
- const coverBuffer = await messages_media_1.toBuffer((await messages_media_1.getStream(cover)).stream)
834
-
835
- const [stickerPackUpload, coverUpload] = await Promise.all([
836
- messages_media_1.encryptedStream(zipBuffer, 'sticker-pack', { logger: options.logger, opts: options.options }),
837
- prepareWAMessageMedia({ image: coverBuffer }, { ...options, mediaTypeOverride: 'image' })
838
- ])
839
-
840
- const stickerPackUploadResult = await options.upload(stickerPackUpload.encFilePath, {
841
- fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
842
- mediaType: 'sticker-pack',
843
- timeoutMs: options.mediaUploadTimeoutMs
844
- })
845
-
846
-
847
- const coverImage = coverUpload.imageMessage
848
- const imageDataHash = crypto_2.sha256(coverBuffer).toString('base64')
849
- const stickerPackId = packId || generics_1.generateMessageID()
850
-
851
- m.stickerPackMessage = {
852
- name,
853
- publisher,
854
- stickerPackId,
855
- packDescription: description,
856
- stickerPackOrigin: WAProto_1.proto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
857
- stickerPackSize: stickerPackUpload.fileLength,
858
- stickers: stickerMetadata,
859
- fileSha256: stickerPackUpload.fileSha256,
860
- fileEncSha256: stickerPackUpload.fileEncSha256,
861
- mediaKey: stickerPackUpload.mediaKey,
862
- directPath: stickerPackUploadResult.directPath,
863
- fileLength: stickerPackUpload.fileLength,
864
- mediaKeyTimestamp: generics_1.unixTimestampSeconds(),
865
- trayIconFileName: `${stickerPackId}.png`,
866
- imageDataHash,
867
- thumbnailDirectPath: coverImage.directPath,
868
- thumbnailFileSha256: coverImage.fileSha256,
869
- thumbnailFileEncSha256: coverImage.fileEncSha256,
870
- thumbnailHeight: coverImage.height,
871
- thumbnailWidth: coverImage.width
872
- }
873
-
874
- m.stickerPackMessage.contextInfo = {
875
- ...(message.contextInfo || {}),
876
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
877
- }
878
- }
879
-
880
- else if ('sharePhoneNumber' in message) {
881
- m.protocolMessage = {
882
- type: Types_1.WAProto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
983
+ if (hasNonNullishProperty(message, "hasMediaAttachment")) {
984
+ interactiveMessage.header.hasMediaAttachment = Boolean(
985
+ message.hasMediaAttachment
986
+ )
987
+ }
988
+ }
883
989
  }
884
- }
885
990
 
886
- else if ('requestPhoneNumber' in message) {
887
- m.requestPhoneNumberMessage = {}
888
- }
991
+ if (hasNonNullishProperty(message, "footer")) {
992
+ interactiveMessage.footer = {
993
+ text: message.footer,
994
+ }
995
+ }
889
996
 
890
- else {
891
- const mess = await prepareWAMessageMedia(message, options)
892
- const [type] = Object.keys(mess)
997
+ m = { interactiveMessage }
998
+ } else if (hasNonNullishProperty(message, "shop")) {
999
+ const interactiveMessage = {
1000
+ shopStorefrontMessage: {
1001
+ surface: message.shop.surface,
1002
+ id: message.shop.id,
1003
+ },
1004
+ }
893
1005
 
894
- mess[type].contextInfo = {
895
- ...(message.contextInfo || {}),
896
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1006
+ if (hasNonNullishProperty(message, "text")) {
1007
+ interactiveMessage.body = {
1008
+ text: message.text,
1009
+ }
897
1010
  }
898
1011
 
899
- m = mess
900
- }
1012
+ if (hasNonNullishProperty(message, "title")) {
1013
+ interactiveMessage.header = {
1014
+ title: message.title,
1015
+ subtitle: null,
1016
+ hasMediaAttachment: false,
1017
+ }
901
1018
 
902
- if ('sections' in message && !!message.sections) {
903
- const listMessage = {
904
- title: message.title,
905
- buttonText: message.buttonText,
906
- footerText: message.footer,
907
- description: message.text,
908
- sections: message.sections,
909
- listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
910
- }
1019
+ if (hasNonNullishProperty(message, "subtitle")) {
1020
+ interactiveMessage.header.subtitle = message.subtitle
1021
+ }
1022
+ } else {
1023
+ if (hasNonNullishProperty(message, "caption")) {
1024
+ interactiveMessage.body = {
1025
+ text: message.caption,
1026
+ }
911
1027
 
912
- listMessage.contextInfo = {
913
- ...(message.contextInfo || {}),
914
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
915
- }
1028
+ interactiveMessage.header = {
1029
+ title: null,
1030
+ subtitle: null,
1031
+ hasMediaAttachment: false,
1032
+ ...Object.assign(interactiveMessage, m),
1033
+ }
916
1034
 
917
- m = { listMessage }
918
- }
1035
+ if (hasNonNullishProperty(message, "title")) {
1036
+ interactiveMessage.header.title = message.title
1037
+ }
919
1038
 
920
- else if ('productList' in message && !!message.productList) {
921
- const thumbnail = message.thumbnail ? await messages_media_1.generateThumbnail(message.thumbnail, 'image') : null
1039
+ if (hasNonNullishProperty(message, "subtitle")) {
1040
+ interactiveMessage.header.subtitle = message.subtitle
1041
+ }
922
1042
 
923
- const listMessage = {
924
- title: message.title,
925
- buttonText: message.buttonText,
926
- footerText: message.footer,
927
- description: message.text,
928
- productListInfo: {
929
- productSections: message.productList,
930
- headerImage: {
931
- productId: message.productList[0].products[0].productId,
932
- jpegThumbnail: thumbnail?.thumbnail || null
933
- },
934
- businessOwnerJid: message.businessOwnerJid
935
- },
936
- listType: WAProto_1.proto.Message.ListMessage.ListType.PRODUCT_LIST
1043
+ if (hasNonNullishProperty(message, "hasMediaAttachment")) {
1044
+ interactiveMessage.header.hasMediaAttachment = Boolean(
1045
+ message.hasMediaAttachment
1046
+ )
1047
+ }
1048
+ }
937
1049
  }
938
1050
 
939
- listMessage.contextInfo = {
940
- ...(message.contextInfo || {}),
941
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1051
+ if (hasNonNullishProperty(message, "footer")) {
1052
+ interactiveMessage.footer = {
1053
+ text: message.footer,
1054
+ }
942
1055
  }
943
1056
 
944
- m = { listMessage }
945
- }
946
-
947
- else if ('buttons' in message && !!message.buttons) {
948
- const buttonsMessage = {
949
- buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
1057
+ m = { interactiveMessage }
1058
+ } else if (hasNonNullishProperty(message, "collection")) {
1059
+ const interactiveMessage = {
1060
+ collectionMessage: {
1061
+ bizJid: message.collection.bizJid,
1062
+ id: message.collection.id,
1063
+ messageVersion: message?.collection?.version,
1064
+ },
950
1065
  }
951
1066
 
952
- if ('text' in message) {
953
- buttonsMessage.contentText = message.text
954
- buttonsMessage.headerType = WAProto_1.proto.Message.ButtonsMessage.HeaderType.EMPTY
1067
+ if (hasNonNullishProperty(message, "text")) {
1068
+ interactiveMessage.body = {
1069
+ text: message.text,
1070
+ }
955
1071
  }
956
1072
 
957
- else {
958
- if ('caption' in message) {
959
- buttonsMessage.contentText = message.caption
1073
+ if (hasNonNullishProperty(message, "title")) {
1074
+ interactiveMessage.header = {
1075
+ title: message.title,
1076
+ subtitle: null,
1077
+ hasMediaAttachment: false,
960
1078
  }
961
1079
 
962
- const type = Object.keys(m)[0].replace('Message', '').toUpperCase()
963
-
964
- buttonsMessage.headerType = WAProto_1.proto.Message.ButtonsMessage.HeaderType[type]
1080
+ if (hasNonNullishProperty(message, "subtitle")) {
1081
+ interactiveMessage.header.subtitle = message.subtitle
1082
+ }
1083
+ } else {
1084
+ if (hasNonNullishProperty(message, "caption")) {
1085
+ interactiveMessage.body = {
1086
+ text: message.caption,
1087
+ }
965
1088
 
966
- Object.assign(buttonsMessage, m)
967
- }
1089
+ interactiveMessage.header = {
1090
+ title: null,
1091
+ subtitle: null,
1092
+ hasMediaAttachment: false,
1093
+ ...Object.assign(interactiveMessage, m),
1094
+ }
968
1095
 
969
- if ('footer' in message && !!message.footer) {
970
- buttonsMessage.footerText = message.footer
971
- }
1096
+ if (hasNonNullishProperty(message, "title")) {
1097
+ interactiveMessage.header.title = message.title
1098
+ }
972
1099
 
973
- if ('title' in message && !!message.title) {
974
- buttonsMessage.text = message.title
975
- buttonsMessage.headerType = WAProto_1.proto.Message.ButtonsMessage.HeaderType.TEXT
976
- }
1100
+ if (hasNonNullishProperty(message, "subtitle")) {
1101
+ interactiveMessage.header.subtitle = message.subtitle
1102
+ }
977
1103
 
978
- buttonsMessage.contextInfo = {
979
- ...(message.contextInfo || {}),
980
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1104
+ if (hasNonNullishProperty(message, "hasMediaAttachment")) {
1105
+ interactiveMessage.header.hasMediaAttachment = Boolean(
1106
+ message.hasMediaAttachment
1107
+ )
1108
+ }
1109
+ }
981
1110
  }
982
1111
 
983
- m = { buttonsMessage }
984
- }
985
-
986
- else if ('templateButtons' in message && !!message.templateButtons) {
987
- const hydratedTemplate = {
988
- hydratedButtons: message.templateButtons
1112
+ if (hasNonNullishProperty(message, "footer")) {
1113
+ interactiveMessage.footer = {
1114
+ text: message.footer,
1115
+ }
989
1116
  }
990
1117
 
991
- if ('text' in message) {
992
- hydratedTemplate.hydratedContentText = message.text
993
- }
1118
+ m = { interactiveMessage }
1119
+ } else if (hasNonNullishProperty(message, "cards")) {
1120
+ const slides = await Promise.all(
1121
+ message.cards.map(async (slide) => {
1122
+ const {
1123
+ image,
1124
+ video,
1125
+ product,
1126
+ title,
1127
+ body,
1128
+ footer,
1129
+ buttons,
1130
+ } = slide
1131
+
1132
+ let header
1133
+
1134
+ if (product) {
1135
+ const { imageMessage } = await prepareWAMessageMedia(
1136
+ { image: product.productImage, ...options },
1137
+ options
1138
+ )
1139
+ header = {
1140
+ productMessage: {
1141
+ product: {
1142
+ ...product,
1143
+ productImage: imageMessage,
1144
+ },
1145
+ ...slide,
1146
+ },
1147
+ }
1148
+ } else if (image) {
1149
+ header = await prepareWAMessageMedia(
1150
+ { image: image, ...options },
1151
+ options
1152
+ )
1153
+ } else if (video) {
1154
+ header = await prepareWAMessageMedia(
1155
+ { video: video, ...options },
1156
+ options
1157
+ )
1158
+ }
994
1159
 
995
- else {
996
- if ('caption' in message) {
997
- hydratedTemplate.hydratedContentText = message.caption
998
- }
1160
+ const msg = {
1161
+ header: {
1162
+ title,
1163
+ hasMediaAttachment: true,
1164
+ ...header,
1165
+ },
1166
+ body: {
1167
+ text: body,
1168
+ },
1169
+ footer: {
1170
+ text: footer,
1171
+ },
1172
+ nativeFlowMessage: {
1173
+ buttons,
1174
+ },
1175
+ }
999
1176
 
1000
- Object.assign(msg, m)
1001
- }
1177
+ return msg
1178
+ })
1179
+ )
1002
1180
 
1003
- if ('footer' in message && !!message.footer) {
1004
- hydratedTemplate.hydratedFooterText = message.footer
1181
+ const interactiveMessage = {
1182
+ carouselMessage: {
1183
+ cards: slides,
1184
+ },
1005
1185
  }
1006
1186
 
1007
- hydratedTemplate.contextInfo = {
1008
- ...(message.contextInfo || {}),
1009
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1187
+ if (hasNonNullishProperty(message, "text")) {
1188
+ interactiveMessage.body = {
1189
+ text: message.text,
1190
+ }
1010
1191
  }
1011
1192
 
1012
- m = { templateMessage: { hydratedTemplate }}
1013
- }
1014
-
1015
- else if ('interactiveButtons' in message && !!message.interactiveButtons) {
1016
- const interactiveMessage = {
1017
- nativeFlowMessage: {
1018
- buttons: message.interactiveButtons
1019
- }
1020
- }
1021
-
1022
- if ('text' in message) {
1023
- interactiveMessage.body = {
1024
- text: message.text
1025
- },
1026
- interactiveMessage.header = {
1027
- title: message.title,
1028
- subtitle: message.subtitle,
1029
- hasMediaAttachment: false
1030
- }
1031
- }
1032
-
1033
- else {
1034
- if ('caption' in message) {
1035
- interactiveMessage.body = {
1036
- text: message.caption
1037
- }
1038
-
1039
- interactiveMessage.header = {
1040
- title: message.title,
1041
- subtitle: message.subtitle,
1042
- hasMediaAttachment: message.hasMediaAttachment ? message.hasMediaAttachment : false,
1043
- ...Object.assign(interactiveMessage, m)
1044
- }
1045
- }
1046
- }
1047
-
1048
- if ('footer' in message && !!message.footer) {
1049
- interactiveMessage.footer = {
1050
- text: message.footer
1051
- }
1052
- }
1053
-
1054
- interactiveMessage.contextInfo = {
1055
- ...(message.contextInfo || {}),
1056
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1057
- }
1058
-
1059
- m = { interactiveMessage }
1060
- }
1061
-
1062
- else if ('shop' in message && !!message.shop) {
1063
- const interactiveMessage = {
1064
- shopStorefrontMessage: {
1065
- surface: message.shop.surface,
1066
- id: message.shop.id
1067
- }
1068
- }
1069
-
1070
- if ('text' in message) {
1071
- interactiveMessage.body = {
1072
- text: message.text
1073
- },
1074
- interactiveMessage.header = {
1075
- title: message.title,
1076
- subtitle: message.subtitle,
1077
- hasMediaAttachment: false
1078
- }
1079
- }
1080
-
1081
- else {
1082
- if ('caption' in message) {
1083
- interactiveMessage.body = {
1084
- text: message.caption
1085
- }
1086
-
1087
- interactiveMessage.header = {
1088
- title: message.title,
1089
- subtitle: message.subtitle,
1090
- hasMediaAttachment: message.hasMediaAttachment ? message.hasMediaAttachment : false,
1091
- ...Object.assign(interactiveMessage, m)
1193
+ if (hasNonNullishProperty(message, "title")) {
1194
+ interactiveMessage.header = {
1195
+ title: message.title,
1196
+ subtitle: null,
1197
+ hasMediaAttachment: false,
1092
1198
  }
1093
- }
1094
- }
1095
-
1096
- if ('footer' in message && !!message.footer) {
1097
- interactiveMessage.footer = {
1098
- text: message.footer
1099
- }
1100
- }
1101
-
1102
- interactiveMessage.contextInfo = {
1103
- ...(message.contextInfo || {}),
1104
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1105
- }
1106
-
1107
- m = { interactiveMessage }
1108
- }
1109
-
1110
- else if ('collection' in message && !!message.collection) {
1111
- const interactiveMessage = {
1112
- collectionMessage: {
1113
- bizJid: message.collection.bizJid,
1114
- id: message.collection.id,
1115
- messageVersion: message?.collection?.version
1116
- }
1117
- }
1118
-
1119
- if ('text' in message) {
1120
- interactiveMessage.body = {
1121
- text: message.text
1122
- },
1123
- interactiveMessage.header = {
1124
- title: message.title,
1125
- subtitle: message.subtitle,
1126
- hasMediaAttachment: false
1127
- }
1128
- }
1129
-
1130
- else {
1131
- if ('caption' in message) {
1132
- interactiveMessage.body = {
1133
- text: message.caption
1134
- }
1135
- interactiveMessage.header = {
1136
- title: message.title,
1137
- subtitle: message.subtitle,
1138
- hasMediaAttachment: message.hasMediaAttachment ? message.hasMediaAttachment : false,
1139
- ...Object.assign(interactiveMessage, m)
1199
+
1200
+ if (hasNonNullishProperty(message, "subtitle")) {
1201
+ interactiveMessage.header.subtitle = message.subtitle
1140
1202
  }
1141
- }
1142
- }
1203
+ } else {
1204
+ if (hasNonNullishProperty(message, "caption")) {
1205
+ interactiveMessage.body = {
1206
+ text: message.caption,
1207
+ }
1143
1208
 
1144
- if ('footer' in message && !message.footer) {
1145
- interactiveMessage.footer = {
1146
- text: message.footer
1147
- }
1148
- }
1209
+ interactiveMessage.header = {
1210
+ title: null,
1211
+ subtitle: null,
1212
+ hasMediaAttachment: false,
1213
+ ...Object.assign(interactiveMessage, m),
1214
+ }
1149
1215
 
1150
- interactiveMessage.contextInfo = {
1151
- ...(message.contextInfo || {}),
1152
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1153
- }
1216
+ if (hasNonNullishProperty(message, "title")) {
1217
+ interactiveMessage.header.title = message.title
1218
+ }
1154
1219
 
1155
- m = { interactiveMessage }
1156
- }
1220
+ if (hasNonNullishProperty(message, "subtitle")) {
1221
+ interactiveMessage.header.subtitle = message.subtitle
1222
+ }
1157
1223
 
1158
- else if ('cards' in message && !!message.cards) {
1159
- const slides = await Promise.all(message.cards.map(async (slide) => {
1160
- const { image, video, product, title, body, footer, buttons } = slide
1161
- let header
1162
-
1163
- if (product) {
1164
- const { imageMessage } = await prepareWAMessageMedia({ image: product.productImage, ...options }, options)
1165
- header = {
1166
- productMessage: {
1167
- product: {
1168
- ...product,
1169
- productImage: imageMessage,
1170
- },
1171
- ...slide
1172
- }
1224
+ if (hasNonNullishProperty(message, "hasMediaAttachment")) {
1225
+ interactiveMessage.header.hasMediaAttachment = Boolean(
1226
+ message.hasMediaAttachment
1227
+ )
1173
1228
  }
1174
1229
  }
1230
+ }
1175
1231
 
1176
- else if (image) {
1177
- header = await prepareWAMessageMedia({ image: image, ...options }, options)
1232
+ if (hasNonNullishProperty(message, "footer")) {
1233
+ interactiveMessage.footer = {
1234
+ text: message.footer,
1178
1235
  }
1236
+ }
1179
1237
 
1180
- else if (video) {
1181
- header = await prepareWAMessageMedia({ video: video, ...options }, options)
1182
- }
1238
+ m = { interactiveMessage }
1239
+ } else if (hasNonNullishProperty(message, "text")) {
1240
+ const extContent = { text: message.text }
1183
1241
 
1184
- const msg = {
1185
- header: {
1186
- title,
1187
- hasMediaAttachment: true,
1188
- ...header
1189
- },
1190
- body: {
1191
- text: body
1192
- },
1193
- footer: {
1194
- text: footer
1195
- },
1196
- nativeFlowMessage: {
1197
- buttons,
1198
- }
1199
- }
1242
+ let urlInfo = message.linkPreview
1200
1243
 
1201
- return msg
1202
- }))
1244
+ if (typeof urlInfo === "undefined") {
1245
+ urlInfo = await generateLinkPreviewIfRequired(
1246
+ message.text,
1247
+ options.getUrlInfo,
1248
+ options.logger
1249
+ )
1250
+ }
1203
1251
 
1204
- const interactiveMessage = {
1205
- carouselMessage: {
1206
- cards: slides
1252
+ if (urlInfo) {
1253
+ extContent.canonicalUrl = urlInfo["canonical-url"]
1254
+ extContent.matchedText = urlInfo["matched-text"]
1255
+ extContent.jpegThumbnail = urlInfo.jpegThumbnail
1256
+ extContent.description = urlInfo.description
1257
+ extContent.title = urlInfo.title
1258
+ extContent.previewType = 0
1259
+
1260
+ const img = urlInfo.highQualityThumbnail
1261
+
1262
+ if (img) {
1263
+ extContent.thumbnailDirectPath = img.directPath
1264
+ extContent.mediaKey = img.mediaKey
1265
+ extContent.mediaKeyTimestamp = img.mediaKeyTimestamp
1266
+ extContent.thumbnailWidth = img.width
1267
+ extContent.thumbnailHeight = img.height
1268
+ extContent.thumbnailSha256 = img.fileSha256
1269
+ extContent.thumbnailEncSha256 = img.fileEncSha256
1207
1270
  }
1208
1271
  }
1209
1272
 
1210
- if ('text' in message) {
1211
- interactiveMessage.body = {
1212
- text: message.text
1213
- },
1214
- interactiveMessage.header = {
1215
- title: message.title,
1216
- subtitle: message.subtitle,
1217
- hasMediaAttachment: false
1218
- }
1273
+ if (options.backgroundColor) {
1274
+ extContent.backgroundArgb = await assertColor(
1275
+ options.backgroundColor
1276
+ )
1219
1277
  }
1220
1278
 
1221
- if ('footer' in message && !!message.footer) {
1222
- interactiveMessage.footer = {
1223
- text: message.footer
1224
- }
1279
+ if (options.textColor) {
1280
+ extContent.textArgb = await assertColor(options.textColor)
1225
1281
  }
1226
1282
 
1227
- interactiveMessage.contextInfo = {
1228
- ...(message.contextInfo || {}),
1229
- ...(message.mentions ? { mentionedJid: message.mentions } : {})
1283
+ if (options.font) {
1284
+ extContent.font = options.font
1230
1285
  }
1231
1286
 
1232
- m = { interactiveMessage }
1287
+ m.extendedTextMessage = extContent
1288
+ } else if (hasMedia) {
1289
+ m = await prepareWAMessageMedia(message, options)
1233
1290
  }
1234
1291
 
1235
- if ('ephemeral' in message && !!message.ephemeral) {
1236
- m = { ephemeralMessage: { message: m } }
1237
- }
1292
+ if (hasOptionalProperty(message, "ephemeral")) {
1293
+ m = { ephemeralMessage: { message: m } }
1294
+ }
1238
1295
 
1239
- if ('viewOnce' in message && !!message.viewOnce) {
1240
- m = { viewOnceMessageV2: { message: m } }
1296
+ if (hasOptionalProperty(message, "mentions") && message.mentions?.length) {
1297
+ const messageType = Object.keys(m)[0]
1298
+ const key = m[messageType]
1299
+
1300
+ if ("contextInfo" in key && !!key.contextInfo) {
1301
+ key.contextInfo.mentionedJid = message.mentions
1302
+ } else if (key) {
1303
+ key.contextInfo = {
1304
+ mentionedJid: message.mentions,
1305
+ }
1306
+ }
1241
1307
  }
1242
1308
 
1243
- if ('viewOnceExt' in message && !!message.viewOnceExt) {
1244
- m = { viewOnceMessageV2Extension: { message: m } }
1309
+ if (hasOptionalProperty(message, "contextInfo") && !!message.contextInfo) {
1310
+ const messageType = Object.keys(m)[0]
1311
+ const key = m[messageType]
1312
+
1313
+ if ("contextInfo" in key && !!key.contextInfo) {
1314
+ key.contextInfo = { ...key.contextInfo, ...message.contextInfo }
1315
+ } else if (key) {
1316
+ key.contextInfo = message.contextInfo
1317
+ }
1245
1318
  }
1246
1319
 
1247
- if ('edit' in message) {
1320
+ if (hasOptionalProperty(message, "edit")) {
1248
1321
  m = {
1249
1322
  protocolMessage: {
1250
1323
  key: message.edit,
1251
1324
  editedMessage: m,
1252
1325
  timestampMs: Date.now(),
1253
- type: Types_1.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
1254
- }
1326
+ type: WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
1327
+ },
1255
1328
  }
1256
1329
  }
1257
1330
 
1258
- return Types_1.WAProto.Message.fromObject(m)
1331
+ return WAProto.Message.fromObject(m)
1259
1332
  }
1260
1333
 
1261
1334
  const generateWAMessageFromContent = (jid, message, options) => {
@@ -1265,11 +1338,11 @@ const generateWAMessageFromContent = (jid, message, options) => {
1265
1338
 
1266
1339
  const innerMessage = normalizeMessageContent(message)
1267
1340
  const key = getContentType(innerMessage)
1268
- const timestamp = generics_1.unixTimestampSeconds(options.timestamp)
1341
+ const timestamp = unixTimestampSeconds(options.timestamp)
1269
1342
  const threadId = []
1270
1343
  const { quoted, userJid } = options
1271
1344
 
1272
- if (quoted && !WABinary_1.isJidNewsletter(jid)) {
1345
+ if (quoted && !isJidNewsletter(jid)) {
1273
1346
  const participant = quoted.key.fromMe
1274
1347
  ? userJid
1275
1348
  : quoted.participant || quoted.key.participant || quoted.key.remoteJid
@@ -1277,7 +1350,7 @@ const generateWAMessageFromContent = (jid, message, options) => {
1277
1350
  let quotedMsg = normalizeMessageContent(quoted.message)
1278
1351
  const msgType = getContentType(quotedMsg)
1279
1352
 
1280
- quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] })
1353
+ quotedMsg = proto.Message.fromObject({ [msgType]: quotedMsg[msgType] })
1281
1354
 
1282
1355
  const quotedContent = quotedMsg[msgType]
1283
1356
 
@@ -1297,7 +1370,7 @@ const generateWAMessageFromContent = (jid, message, options) => {
1297
1370
 
1298
1371
  const contextInfo = (key === 'requestPaymentMessage' ? requestPayment?.contextInfo : innerMessage[key].contextInfo) || {}
1299
1372
 
1300
- contextInfo.participant = WABinary_1.jidNormalizedUser(participant)
1373
+ contextInfo.participant = jidNormalizedUser(participant)
1301
1374
  contextInfo.stanzaId = quoted.key.id
1302
1375
  contextInfo.quotedMessage = quotedMsg
1303
1376
 
@@ -1306,16 +1379,16 @@ const generateWAMessageFromContent = (jid, message, options) => {
1306
1379
  }
1307
1380
 
1308
1381
  if (contextInfo.quotedMessage) {
1309
- contextInfo.quotedType = WAProto_1.proto.ContextInfo.QuotedType.EXPLICIT
1382
+ contextInfo.quotedType = proto.ContextInfo.QuotedType.EXPLICIT
1310
1383
  }
1311
1384
 
1312
- if (contextInfo.quotedMessage && WABinary_1.isJidGroup(jid)) {
1385
+ if (contextInfo.quotedMessage && isJidGroup(jid)) {
1313
1386
  threadId.push({
1314
- threadType: WAProto_1.proto.ThreadID.ThreadType.VIEW_REPLIES,
1387
+ threadType: proto.ThreadID.ThreadType.VIEW_REPLIES,
1315
1388
  threadKey: {
1316
1389
  remoteJid: quoted?.key?.remoteJid,
1317
1390
  fromMe: quoted?.key?.fromMe,
1318
- id: generics_1.generateMessageID(),
1391
+ id: generateMessageID(),
1319
1392
  ...(quoted?.key?.fromMe ? {} : { participant: quoted?.key?.participant })
1320
1393
  }
1321
1394
  })
@@ -1330,10 +1403,10 @@ const generateWAMessageFromContent = (jid, message, options) => {
1330
1403
 
1331
1404
  if (key !== 'protocolMessage' &&
1332
1405
  key !== 'ephemeralMessage' &&
1333
- !WABinary_1.isJidNewsletter(jid)) {
1406
+ !isJidNewsletter(jid)) {
1334
1407
  message.messageContextInfo = {
1335
1408
  threadId: threadId.length > 0 ? threadId : [],
1336
- messageSecret: crypto_1.randomBytes(32),
1409
+ messageSecret: randomBytes(32),
1337
1410
  ...message.messageContextInfo
1338
1411
  }
1339
1412
  innerMessage[key].contextInfo = {
@@ -1342,34 +1415,34 @@ const generateWAMessageFromContent = (jid, message, options) => {
1342
1415
  }
1343
1416
  }
1344
1417
 
1345
- message = Types_1.WAProto.Message.fromObject(message)
1418
+ message = WAProto.Message.fromObject(message)
1346
1419
 
1347
1420
  const messageJSON = {
1348
1421
  key: {
1349
1422
  remoteJid: jid,
1350
1423
  fromMe: true,
1351
- id: options?.messageId || generics_1.generateMessageID()
1424
+ id: options?.messageId || generateMessageID()
1352
1425
  },
1353
1426
  message: message,
1354
1427
  messageTimestamp: timestamp,
1355
1428
  messageStubParameters: [],
1356
- participant: WABinary_1.isJidGroup(jid) || WABinary_1.isJidStatusBroadcast(jid) ? userJid : undefined,
1357
- status: Types_1.WAMessageStatus.PENDING
1429
+ participant: isJidGroup(jid) || isJidStatusBroadcast(jid) ? userJid : undefined,
1430
+ status: WAMessageStatus.PENDING
1358
1431
  }
1359
1432
 
1360
- return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON)
1433
+ return WAProto.WebMessageInfo.fromObject(messageJSON)
1361
1434
  }
1362
1435
 
1363
1436
  const generateWAMessage = async (jid, content, options) => {
1364
1437
  options.logger = options?.logger?.child({ msgId: options.messageId })
1365
1438
 
1366
- return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { newsletter: WABinary_1.isJidNewsletter(jid), ...options }), options)
1439
+ return generateWAMessageFromContent(jid, await generateWAMessageContent(content, { newsletter: isJidNewsletter(jid), ...options }), options)
1367
1440
  }
1368
1441
 
1369
1442
  const getContentType = (content) => {
1370
1443
  if (content) {
1371
1444
  const keys = Object.keys(content)
1372
- const key = keys.find(k => (k === 'conversation' || k.endsWith('Message') || k.endsWith('V2') || k.endsWith('V3') || k.endsWith('V4') || k.endsWith('V5')) && k !== 'senderKeyDistributionMessage' && k !== 'messageContextInfo')
1445
+ const key = keys.find(k => (k === 'conversation' || k.endsWith('Message') || k.endsWith('V2') || k.endsWith('V3') || k.endsWith('V4')) && k !== 'senderKeyDistributionMessage' && k !== 'messageContextInfo')
1373
1446
 
1374
1447
  return key
1375
1448
  }
@@ -1416,7 +1489,6 @@ const normalizeMessageContent = (content) => {
1416
1489
  || (message?.statusMentionMessage)
1417
1490
  || (message?.groupStatusMessageV2)
1418
1491
  || (message?.pollCreationMessageV4)
1419
- || (message?.pollCreationMessageV5)
1420
1492
  || (message?.associatedChildMessage)
1421
1493
  || (message?.groupMentionedMessage)
1422
1494
  || (message?.groupStatusMentionMessage)
@@ -1517,9 +1589,9 @@ const updateMessageWithReceipt = (msg, receipt) => {
1517
1589
 
1518
1590
  /** Update the message with a new reaction */
1519
1591
  const updateMessageWithReaction = (msg, reaction) => {
1520
- const authorID = generics_1.getKeyAuthor(reaction.key)
1592
+ const authorID = getKeyAuthor(reaction.key)
1521
1593
  const reactions = (msg.reactions || [])
1522
- .filter(r => generics_1.getKeyAuthor(r.key) !== authorID)
1594
+ .filter(r => getKeyAuthor(r.key) !== authorID)
1523
1595
 
1524
1596
  reaction.text = reaction.text || ''
1525
1597
  reactions.push(reaction)
@@ -1528,9 +1600,9 @@ const updateMessageWithReaction = (msg, reaction) => {
1528
1600
 
1529
1601
  /** Update the message with a new poll update */
1530
1602
  const updateMessageWithPollUpdate = (msg, update) => {
1531
- const authorID = generics_1.getKeyAuthor(update.pollUpdateMessageKey)
1603
+ const authorID = getKeyAuthor(update.pollUpdateMessageKey)
1532
1604
  const votes = (msg.pollUpdates || [])
1533
- .filter(r => generics_1.getKeyAuthor(r.pollUpdateMessageKey) !== authorID)
1605
+ .filter(r => getKeyAuthor(r.pollUpdateMessageKey) !== authorID)
1534
1606
 
1535
1607
  if (update.vote?.selectedOptions?.length) {
1536
1608
  votes.push(update)
@@ -1541,10 +1613,10 @@ const updateMessageWithPollUpdate = (msg, update) => {
1541
1613
 
1542
1614
  /** Update the message with a new event response*/
1543
1615
  const updateMessageWithEventResponse = (msg, update) => {
1544
- const authorID = generics_1.getKeyAuthor(update.eventResponseMessageKey)
1616
+ const authorID = getKeyAuthor(update.eventResponseMessageKey)
1545
1617
  const responses = (msg.eventResponses || [])
1546
- .filter(r => generics_1.getKeyAuthor(r.eventResponseMessageKey) !== authorID)
1547
-
1618
+ .filter(r => getKeyAuthor(r.eventResponseMessageKey) !== authorID)
1619
+
1548
1620
  responses.push(update)
1549
1621
  msg.eventResponses = responses
1550
1622
  }
@@ -1561,7 +1633,7 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1561
1633
  const opts = message?.pollCreationMessage?.options || message?.pollCreationMessageV2?.options || message?.pollCreationMessageV3?.options || []
1562
1634
 
1563
1635
  const voteHashMap = opts.reduce((acc, opt) => {
1564
- const hash = crypto_2.sha256(Buffer.from(opt.optionName || '')).toString()
1636
+ const hash = sha256(Buffer.from(opt.optionName || '')).toString()
1565
1637
  acc[hash] = {
1566
1638
  name: opt.optionName || '',
1567
1639
  voters: []
@@ -1590,7 +1662,7 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1590
1662
  data = voteHashMap[hash]
1591
1663
  }
1592
1664
 
1593
- voteHashMap[hash].voters.push(generics_1.getKeyAuthor(update.pollUpdateMessageKey, meId))
1665
+ voteHashMap[hash].voters.push(getKeyAuthor(update.pollUpdateMessageKey, meId))
1594
1666
  }
1595
1667
  }
1596
1668
 
@@ -1608,18 +1680,18 @@ function getAggregateResponsesInEventMessage({ eventResponses }, meLid) {
1608
1680
  const responseMap = {}
1609
1681
 
1610
1682
  for (const type of responseTypes) {
1611
- responseMap[type] = {
1612
- response: type,
1613
- responders: []
1614
- }
1683
+ responseMap[type] = {
1684
+ response: type,
1685
+ responders: []
1686
+ }
1615
1687
  }
1616
-
1688
+
1617
1689
  for (const update of eventResponses) {
1618
- const { response } = update.response || 0
1619
- const responseType = WAProto_1.proto.Message.EventResponseMessage.EventResponseType[response]
1620
- if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
1621
- responseMap[responseType].responders.push(generics_1.getKeyAuthor(update.eventResponseMessageKey, meLid))
1622
- }
1690
+ const { response } = update.response || 0
1691
+ const responseType = proto.Message.EventResponseMessage.EventResponseType[response]
1692
+ if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
1693
+ responseMap[responseType].responders.push(getKeyAuthor(update.eventResponseMessageKey, meLid))
1694
+ }
1623
1695
  }
1624
1696
 
1625
1697
  return Object.values(responseMap)
@@ -1655,40 +1727,42 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404]
1655
1727
  */
1656
1728
  const downloadMediaMessage = async (message, type, options, ctx) => {
1657
1729
  const result = await downloadMsg().catch(async (error) => {
1658
- if (ctx && axios_1.default.isAxiosError(error) && // check if the message requires a reupload
1659
- REUPLOAD_REQUIRED_STATUS.includes(error.response?.status)) {
1730
+ if (ctx &&
1731
+ typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1732
+ REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
1660
1733
  ctx.logger.info({ key: message.key }, 'sending reupload media request...')
1661
-
1734
+
1662
1735
  // request reupload
1663
1736
  message = await ctx.reuploadRequest(message)
1664
-
1737
+
1665
1738
  const result = await downloadMsg()
1666
-
1667
1739
  return result
1668
1740
  }
1669
-
1741
+
1670
1742
  throw error
1671
1743
  })
1672
-
1744
+
1673
1745
  return result
1674
-
1746
+
1675
1747
  async function downloadMsg() {
1676
1748
  const mContent = extractMessageContent(message.message)
1677
-
1749
+
1678
1750
  if (!mContent) {
1679
- throw new boom_1.Boom('No message present', { statusCode: 400, data: message })
1751
+ throw new Boom('No message present', { statusCode: 400, data: message })
1680
1752
  }
1681
-
1753
+
1682
1754
  const contentType = getContentType(mContent)
1755
+
1683
1756
  let mediaType = contentType?.replace('Message', '')
1757
+
1684
1758
  const media = contentType === 'productMessage' ? mContent[contentType]?.product?.productImage : mContent[contentType]
1685
-
1759
+
1686
1760
  if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
1687
- throw new boom_1.Boom(`"${contentType}" message is not a media message`)
1761
+ throw new Boom(`"${contentType}" message is not a media message`)
1688
1762
  }
1689
-
1763
+
1690
1764
  let download
1691
-
1765
+
1692
1766
  if ('thumbnailDirectPath' in media && !('url' in media)) {
1693
1767
  download = {
1694
1768
  directPath: media.thumbnailDirectPath,
@@ -1696,68 +1770,40 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
1696
1770
  }
1697
1771
  mediaType = 'thumbnail-link'
1698
1772
  }
1699
-
1700
1773
  else {
1701
1774
  download = media
1702
1775
  }
1703
-
1704
- const stream = await messages_media_1.downloadContentFromMessage(download, mediaType, options)
1705
-
1776
+
1777
+ const stream = await downloadContentFromMessage(download, mediaType, options)
1778
+
1706
1779
  if (type === 'buffer') {
1707
1780
  const bufferArray = []
1708
-
1709
1781
  for await (const chunk of stream) {
1710
- bufferArray.push(chunk)
1782
+ bufferArray.push(chunk);
1711
1783
  }
1712
-
1713
- return Buffer.concat(bufferArray)
1784
+ return Buffer.concat(bufferArray);
1714
1785
  }
1715
-
1716
1786
  return stream
1717
1787
  }
1718
1788
  }
1719
1789
 
1720
- /** Checks whether the given message is a media message if it is returns the inner content */
1790
+ /** Checks whether the given message is a media message; if it is returns the inner content */
1721
1791
  const assertMediaContent = (content) => {
1722
1792
  content = extractMessageContent(content)
1723
-
1724
- const mediaContent = content?.documentMessage
1725
- || content?.imageMessage
1726
- || content?.videoMessage
1727
- || content?.audioMessage
1728
- || content?.stickerMessage
1729
-
1793
+
1794
+ const mediaContent = content?.documentMessage ||
1795
+ content?.imageMessage ||
1796
+ content?.videoMessage ||
1797
+ content?.audioMessage ||
1798
+ content?.stickerMessage
1799
+
1730
1800
  if (!mediaContent) {
1731
- throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content })
1801
+ throw new Boom('given message is not a media message', { statusCode: 400, data: content });
1732
1802
  }
1803
+
1733
1804
  return mediaContent
1734
1805
  }
1735
1806
 
1736
- /**
1737
- * this is an experimental patch to make buttons work
1738
- * Don't know how it works, but it does for now
1739
- */
1740
- const patchMessageForMdIfRequired = (message) => {
1741
- if (message?.buttonsMessage ||
1742
- message?.templateMessage ||
1743
- message?.listMessage ||
1744
- message?.interactiveMessage?.nativeFlowMesaage
1745
- ) {
1746
- message = {
1747
- viewOnceMessageV2Extension: {
1748
- message: {
1749
- messageContextInfo: {
1750
- deviceListMetadataVersion: 2,
1751
- deviceListMetadata: {}
1752
- },
1753
- ...message
1754
- }
1755
- }
1756
- }
1757
- }
1758
- return message
1759
- }
1760
-
1761
1807
  module.exports = {
1762
1808
  extractUrlFromText,
1763
1809
  generateLinkPreviewIfRequired,
@@ -1769,6 +1815,7 @@ module.exports = {
1769
1815
  generateWAMessageFromContent,
1770
1816
  generateWAMessage,
1771
1817
  getContentType,
1818
+ hasNonNullishProperty,
1772
1819
  normalizeMessageContent,
1773
1820
  extractMessageContent,
1774
1821
  getDevice,
@@ -1780,6 +1827,5 @@ module.exports = {
1780
1827
  getAggregateResponsesInEventMessage,
1781
1828
  aggregateMessageKeysNotFromMe,
1782
1829
  downloadMediaMessage,
1783
- assertMediaContent,
1784
- patchMessageForMdIfRequired
1830
+ assertMediaContent
1785
1831
  }