@deffa5556/bail 1.0.6 → 1.0.7

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 (314) hide show
  1. package/cjs/WAProto/index.cjs +106053 -0
  2. package/cjs/deffa/config.cjs +14 -0
  3. package/cjs/deffa/plugins/ai/deepseekr1.cjs +35 -0
  4. package/cjs/deffa/plugins/ai/gita.cjs +26 -0
  5. package/cjs/deffa/plugins/ai/glm47flash.cjs +35 -0
  6. package/cjs/deffa/plugins/ai/gptoss120b.cjs +35 -0
  7. package/cjs/deffa/plugins/ai/qwq32b.cjs +35 -0
  8. package/cjs/deffa/plugins/berita/antara.cjs +25 -0
  9. package/cjs/deffa/plugins/berita/cnbcindonesia.cjs +25 -0
  10. package/cjs/deffa/plugins/berita/cnn.cjs +25 -0
  11. package/cjs/deffa/plugins/berita/kompas.cjs +25 -0
  12. package/cjs/deffa/plugins/berita/liputan6.cjs +25 -0
  13. package/cjs/deffa/plugins/berita/merdeka.cjs +25 -0
  14. package/cjs/deffa/plugins/berita/sindonews.cjs +25 -0
  15. package/cjs/deffa/plugins/berita/tribunnews.cjs +25 -0
  16. package/cjs/deffa/plugins/downloader/douyin.cjs +30 -0
  17. package/cjs/deffa/plugins/downloader/facebook.cjs +30 -0
  18. package/cjs/deffa/plugins/downloader/github.cjs +35 -0
  19. package/cjs/deffa/plugins/downloader/lahelu.cjs +30 -0
  20. package/cjs/deffa/plugins/downloader/snackvideo.cjs +30 -0
  21. package/cjs/deffa/plugins/downloader/soundcloud.cjs +30 -0
  22. package/cjs/deffa/plugins/downloader/tiktok.cjs +30 -0
  23. package/cjs/deffa/plugins/downloader/tiktokhd.cjs +30 -0
  24. package/cjs/deffa/plugins/downloader/twitter.cjs +30 -0
  25. package/cjs/deffa/plugins/downloader/ummy.cjs +36 -0
  26. package/cjs/deffa/plugins/index.cjs +213 -0
  27. package/cjs/deffa/plugins/info/bmkg.cjs +34 -0
  28. package/cjs/deffa/plugins/info/cuaca.cjs +31 -0
  29. package/cjs/deffa/plugins/info/jadwaltv.cjs +29 -0
  30. package/cjs/deffa/plugins/maker/brat.cjs +45 -0
  31. package/cjs/deffa/plugins/maker/bratvid.cjs +52 -0
  32. package/cjs/deffa/plugins/search/8font.cjs +28 -0
  33. package/cjs/deffa/plugins/search/applemusic.cjs +28 -0
  34. package/cjs/deffa/plugins/search/bimg.cjs +30 -0
  35. package/cjs/deffa/plugins/search/brave.cjs +34 -0
  36. package/cjs/deffa/plugins/search/duckduckgo.cjs +28 -0
  37. package/cjs/deffa/plugins/search/lahelu.cjs +28 -0
  38. package/cjs/deffa/plugins/search/mangatoon.cjs +28 -0
  39. package/cjs/deffa/plugins/search/mcpedl.cjs +28 -0
  40. package/cjs/deffa/plugins/search/myinstants.cjs +28 -0
  41. package/cjs/deffa/plugins/search/otakotaku.cjs +28 -0
  42. package/cjs/deffa/plugins/search/pinterest.cjs +30 -0
  43. package/cjs/deffa/plugins/search/resep.cjs +28 -0
  44. package/cjs/deffa/plugins/search/seegore.cjs +30 -0
  45. package/cjs/deffa/plugins/search/soundcloud.cjs +28 -0
  46. package/cjs/deffa/plugins/search/youtube.cjs +28 -0
  47. package/cjs/deffa/plugins/stalk/github.cjs +38 -0
  48. package/cjs/deffa/plugins/stalk/pinterest.cjs +37 -0
  49. package/cjs/deffa/plugins/stalk/threads.cjs +34 -0
  50. package/cjs/deffa/plugins/stalk/tiktok.cjs +37 -0
  51. package/cjs/deffa/plugins/stalk/twitter.cjs +37 -0
  52. package/cjs/deffa/plugins/stalk/youtube.cjs +37 -0
  53. package/cjs/lib/Defaults/index.cjs +158 -0
  54. package/cjs/lib/Discord/Client.cjs +263 -0
  55. package/cjs/lib/Discord/Constants.cjs +1842 -0
  56. package/cjs/lib/Discord/connect-dc.cjs +11 -0
  57. package/cjs/lib/Discord/esm-bridge.cjs +136 -0
  58. package/cjs/lib/Discord/gateway/Dispatcher.cjs +93 -0
  59. package/cjs/lib/Discord/gateway/Shard.cjs +695 -0
  60. package/cjs/lib/Discord/gateway/ShardManager.cjs +344 -0
  61. package/cjs/lib/Discord/gateway/compression/base.cjs +13 -0
  62. package/cjs/lib/Discord/gateway/compression/config.cjs +47 -0
  63. package/cjs/lib/Discord/gateway/compression/pako.cjs +44 -0
  64. package/cjs/lib/Discord/gateway/compression/zlib-native.cjs +47 -0
  65. package/cjs/lib/Discord/gateway/compression/zlib-sync.cjs +31 -0
  66. package/cjs/lib/Discord/gateway/compression/zstd-napi.cjs +80 -0
  67. package/cjs/lib/Discord/gateway/compression/zstd-native.cjs +46 -0
  68. package/cjs/lib/Discord/gateway/events.cjs +956 -0
  69. package/cjs/lib/Discord/index.cjs +238 -0
  70. package/cjs/lib/Discord/rest/Bucket.cjs +69 -0
  71. package/cjs/lib/Discord/rest/DiscordHTTPError.cjs +63 -0
  72. package/cjs/lib/Discord/rest/DiscordRESTError.cjs +84 -0
  73. package/cjs/lib/Discord/rest/OAuthHelper.cjs +226 -0
  74. package/cjs/lib/Discord/rest/RESTManager.cjs +116 -0
  75. package/cjs/lib/Discord/rest/RequestHandler.cjs +320 -0
  76. package/cjs/lib/Discord/rest/SequentialBucket.cjs +69 -0
  77. package/cjs/lib/Discord/routes/Applications.cjs +625 -0
  78. package/cjs/lib/Discord/routes/Channels.cjs +1199 -0
  79. package/cjs/lib/Discord/routes/Guilds.cjs +1792 -0
  80. package/cjs/lib/Discord/routes/Interactions.cjs +212 -0
  81. package/cjs/lib/Discord/routes/Lobbies.cjs +197 -0
  82. package/cjs/lib/Discord/routes/Miscellaneous.cjs +120 -0
  83. package/cjs/lib/Discord/routes/OAuth.cjs +350 -0
  84. package/cjs/lib/Discord/routes/Users.cjs +107 -0
  85. package/cjs/lib/Discord/routes/Webhooks.cjs +308 -0
  86. package/cjs/lib/Discord/structures/AnnouncementChannel.cjs +46 -0
  87. package/cjs/lib/Discord/structures/AnnouncementThreadChannel.cjs +28 -0
  88. package/cjs/lib/Discord/structures/Application.cjs +345 -0
  89. package/cjs/lib/Discord/structures/ApplicationCommand.cjs +109 -0
  90. package/cjs/lib/Discord/structures/Attachment.cjs +46 -0
  91. package/cjs/lib/Discord/structures/AuditLogEntry.cjs +41 -0
  92. package/cjs/lib/Discord/structures/AutoModerationRule.cjs +117 -0
  93. package/cjs/lib/Discord/structures/AutocompleteInteraction.cjs +90 -0
  94. package/cjs/lib/Discord/structures/Base.cjs +56 -0
  95. package/cjs/lib/Discord/structures/BaseEntitlement.cjs +40 -0
  96. package/cjs/lib/Discord/structures/CategoryChannel.cjs +102 -0
  97. package/cjs/lib/Discord/structures/Channel.cjs +89 -0
  98. package/cjs/lib/Discord/structures/ClientApplication.cjs +269 -0
  99. package/cjs/lib/Discord/structures/CommandInteraction.cjs +294 -0
  100. package/cjs/lib/Discord/structures/ComponentInteraction.cjs +306 -0
  101. package/cjs/lib/Discord/structures/Entitlement.cjs +24 -0
  102. package/cjs/lib/Discord/structures/ExtendedUser.cjs +48 -0
  103. package/cjs/lib/Discord/structures/ForumChannel.cjs +20 -0
  104. package/cjs/lib/Discord/structures/GroupChannel.cjs +160 -0
  105. package/cjs/lib/Discord/structures/Guild.cjs +1289 -0
  106. package/cjs/lib/Discord/structures/GuildChannel.cjs +82 -0
  107. package/cjs/lib/Discord/structures/GuildPreview.cjs +141 -0
  108. package/cjs/lib/Discord/structures/GuildScheduledEvent.cjs +166 -0
  109. package/cjs/lib/Discord/structures/GuildTemplate.cjs +96 -0
  110. package/cjs/lib/Discord/structures/Integration.cjs +123 -0
  111. package/cjs/lib/Discord/structures/Interaction.cjs +78 -0
  112. package/cjs/lib/Discord/structures/InteractionResolvedChannel.cjs +36 -0
  113. package/cjs/lib/Discord/structures/Invite.cjs +196 -0
  114. package/cjs/lib/Discord/structures/InviteGuild.cjs +117 -0
  115. package/cjs/lib/Discord/structures/InviteRole.cjs +88 -0
  116. package/cjs/lib/Discord/structures/Lobby.cjs +84 -0
  117. package/cjs/lib/Discord/structures/LobbyMember.cjs +30 -0
  118. package/cjs/lib/Discord/structures/MediaChannel.cjs +20 -0
  119. package/cjs/lib/Discord/structures/Member.cjs +300 -0
  120. package/cjs/lib/Discord/structures/Message.cjs +553 -0
  121. package/cjs/lib/Discord/structures/ModalSubmitInteraction.cjs +263 -0
  122. package/cjs/lib/Discord/structures/OAuthApplication.cjs +203 -0
  123. package/cjs/lib/Discord/structures/OAuthGuild.cjs +98 -0
  124. package/cjs/lib/Discord/structures/PartialApplication.cjs +97 -0
  125. package/cjs/lib/Discord/structures/Permission.cjs +61 -0
  126. package/cjs/lib/Discord/structures/PermissionOverwrite.cjs +46 -0
  127. package/cjs/lib/Discord/structures/PingInteraction.cjs +27 -0
  128. package/cjs/lib/Discord/structures/Poll.cjs +69 -0
  129. package/cjs/lib/Discord/structures/PrimaryGuild.cjs +93 -0
  130. package/cjs/lib/Discord/structures/PrivateChannel.cjs +131 -0
  131. package/cjs/lib/Discord/structures/PrivateThreadChannel.cjs +28 -0
  132. package/cjs/lib/Discord/structures/PublicThreadChannel.cjs +36 -0
  133. package/cjs/lib/Discord/structures/Role.cjs +126 -0
  134. package/cjs/lib/Discord/structures/SKU.cjs +58 -0
  135. package/cjs/lib/Discord/structures/Soundboard.cjs +58 -0
  136. package/cjs/lib/Discord/structures/StageChannel.cjs +45 -0
  137. package/cjs/lib/Discord/structures/StageInstance.cjs +80 -0
  138. package/cjs/lib/Discord/structures/Subscription.cjs +21 -0
  139. package/cjs/lib/Discord/structures/Team.cjs +70 -0
  140. package/cjs/lib/Discord/structures/TestEntitlement.cjs +22 -0
  141. package/cjs/lib/Discord/structures/TextChannel.cjs +48 -0
  142. package/cjs/lib/Discord/structures/TextableChannel.cjs +265 -0
  143. package/cjs/lib/Discord/structures/TextableVoiceChannel.cjs +70 -0
  144. package/cjs/lib/Discord/structures/ThreadChannel.cjs +276 -0
  145. package/cjs/lib/Discord/structures/ThreadOnlyChannel.cjs +205 -0
  146. package/cjs/lib/Discord/structures/ThreadableChannel.cjs +57 -0
  147. package/cjs/lib/Discord/structures/UnavailableGuild.cjs +21 -0
  148. package/cjs/lib/Discord/structures/User.cjs +223 -0
  149. package/cjs/lib/Discord/structures/VoiceChannel.cjs +34 -0
  150. package/cjs/lib/Discord/structures/VoiceState.cjs +113 -0
  151. package/cjs/lib/Discord/structures/Webhook.cjs +224 -0
  152. package/cjs/lib/Discord/util/Collection.cjs +77 -0
  153. package/cjs/lib/Discord/util/Errors.cjs +81 -0
  154. package/cjs/lib/Discord/util/QueryBuilder.cjs +20 -0
  155. package/cjs/lib/Discord/util/Routes.cjs +293 -0
  156. package/cjs/lib/Discord/util/SimpleCollection.cjs +78 -0
  157. package/cjs/lib/Discord/util/Time.cjs +92 -0
  158. package/cjs/lib/Discord/util/TypedCollection.cjs +78 -0
  159. package/cjs/lib/Discord/util/TypedEmitter.cjs +20 -0
  160. package/cjs/lib/Discord/util/Util.cjs +906 -0
  161. package/cjs/lib/Discord/util/interactions/InteractionOptionsWrapper.cjs +207 -0
  162. package/cjs/lib/Discord/util/interactions/MessageInteractionResponse.cjs +26 -0
  163. package/cjs/lib/Discord/util/interactions/ModalSubmitInteractionComponentsWrapper.cjs +98 -0
  164. package/cjs/lib/Discord/util/interactions/SelectMenuValuesWrapper.cjs +77 -0
  165. package/cjs/lib/Discord/util/interactions/shared.cjs +20 -0
  166. package/cjs/lib/Discord/util/warning.cjs +34 -0
  167. package/cjs/lib/Signal/Group/ciphertext-message.cjs +16 -0
  168. package/cjs/lib/Signal/Group/group-session-builder.cjs +67 -0
  169. package/cjs/lib/Signal/Group/group_cipher.cjs +86 -0
  170. package/cjs/lib/Signal/Group/index.cjs +58 -0
  171. package/cjs/lib/Signal/Group/keyhelper.cjs +56 -0
  172. package/cjs/lib/Signal/Group/sender-chain-key.cjs +30 -0
  173. package/cjs/lib/Signal/Group/sender-key-distribution-message.cjs +67 -0
  174. package/cjs/lib/Signal/Group/sender-key-message.cjs +70 -0
  175. package/cjs/lib/Signal/Group/sender-key-name.cjs +52 -0
  176. package/cjs/lib/Signal/Group/sender-key-record.cjs +45 -0
  177. package/cjs/lib/Signal/Group/sender-key-state.cjs +88 -0
  178. package/cjs/lib/Signal/Group/sender-message-key.cjs +30 -0
  179. package/cjs/lib/Signal/libsignal.cjs +467 -0
  180. package/cjs/lib/Signal/lid-mapping.cjs +281 -0
  181. package/cjs/lib/Socket/Client/index.cjs +19 -0
  182. package/cjs/lib/Socket/Client/types.cjs +15 -0
  183. package/cjs/lib/Socket/Client/websocket.cjs +61 -0
  184. package/cjs/lib/Socket/business.cjs +384 -0
  185. package/cjs/lib/Socket/chats.cjs +1221 -0
  186. package/cjs/lib/Socket/communities.cjs +440 -0
  187. package/cjs/lib/Socket/groups.cjs +353 -0
  188. package/cjs/lib/Socket/index.cjs +14 -0
  189. package/cjs/lib/Socket/messages-recv.cjs +1772 -0
  190. package/cjs/lib/Socket/messages-send.cjs +1376 -0
  191. package/cjs/lib/Socket/mex.cjs +46 -0
  192. package/cjs/lib/Socket/newsletter.cjs +230 -0
  193. package/cjs/lib/Socket/socket.cjs +976 -0
  194. package/cjs/lib/Store/index.cjs +20 -0
  195. package/cjs/lib/Store/make-in-memory-store.cjs +470 -0
  196. package/cjs/lib/Store/make-ordered-dictionary.cjs +82 -0
  197. package/cjs/lib/Store/object-repository.cjs +28 -0
  198. package/cjs/lib/Telegram/button.cjs +147 -0
  199. package/cjs/lib/Telegram/composer.cjs +582 -0
  200. package/cjs/lib/Telegram/context.cjs +853 -0
  201. package/cjs/lib/Telegram/core/helpers/args.cjs +57 -0
  202. package/cjs/lib/Telegram/core/helpers/check.cjs +55 -0
  203. package/cjs/lib/Telegram/core/helpers/compact.cjs +16 -0
  204. package/cjs/lib/Telegram/core/helpers/deunionize.cjs +12 -0
  205. package/cjs/lib/Telegram/core/helpers/formatting.cjs +91 -0
  206. package/cjs/lib/Telegram/core/helpers/util.cjs +50 -0
  207. package/cjs/lib/Telegram/core/network/client.cjs +338 -0
  208. package/cjs/lib/Telegram/core/network/error.cjs +21 -0
  209. package/cjs/lib/Telegram/core/network/multipart-stream.cjs +79 -0
  210. package/cjs/lib/Telegram/core/network/polling.cjs +87 -0
  211. package/cjs/lib/Telegram/core/network/webhook.cjs +54 -0
  212. package/cjs/lib/Telegram/core/types/typegram.cjs +31 -0
  213. package/cjs/lib/Telegram/deffa-telegraf.cjs +264 -0
  214. package/cjs/lib/Telegram/esm-bridge.cjs +20 -0
  215. package/cjs/lib/Telegram/filters.cjs +69 -0
  216. package/cjs/lib/Telegram/format.cjs +58 -0
  217. package/cjs/lib/Telegram/future.cjs +140 -0
  218. package/cjs/lib/Telegram/index.cjs +67 -0
  219. package/cjs/lib/Telegram/input.cjs +61 -0
  220. package/cjs/lib/Telegram/markup.cjs +129 -0
  221. package/cjs/lib/Telegram/middleware.cjs +2 -0
  222. package/cjs/lib/Telegram/reactions.cjs +84 -0
  223. package/cjs/lib/Telegram/router.cjs +46 -0
  224. package/cjs/lib/Telegram/scenes/base.cjs +39 -0
  225. package/cjs/lib/Telegram/scenes/context.cjs +104 -0
  226. package/cjs/lib/Telegram/scenes/index.cjs +21 -0
  227. package/cjs/lib/Telegram/scenes/stage.cjs +49 -0
  228. package/cjs/lib/Telegram/scenes/wizard/context.cjs +31 -0
  229. package/cjs/lib/Telegram/scenes/wizard/index.cjs +45 -0
  230. package/cjs/lib/Telegram/scenes.cjs +21 -0
  231. package/cjs/lib/Telegram/session.cjs +166 -0
  232. package/cjs/lib/Telegram/telegram-types.cjs +6 -0
  233. package/cjs/lib/Telegram/telegram.cjs +945 -0
  234. package/cjs/lib/Telegram/types.cjs +2 -0
  235. package/cjs/lib/Telegram/utils.cjs +5 -0
  236. package/cjs/lib/Types/Auth.cjs +3 -0
  237. package/cjs/lib/Types/Bussines.cjs +3 -0
  238. package/cjs/lib/Types/Call.cjs +3 -0
  239. package/cjs/lib/Types/Chat.cjs +11 -0
  240. package/cjs/lib/Types/Contact.cjs +3 -0
  241. package/cjs/lib/Types/Events.cjs +4 -0
  242. package/cjs/lib/Types/GroupMetadata.cjs +3 -0
  243. package/cjs/lib/Types/Label.cjs +26 -0
  244. package/cjs/lib/Types/LabelAssociation.cjs +8 -0
  245. package/cjs/lib/Types/Message.cjs +19 -0
  246. package/cjs/lib/Types/Mex.cjs +40 -0
  247. package/cjs/lib/Types/Product.cjs +3 -0
  248. package/cjs/lib/Types/RichType.cjs +24 -0
  249. package/cjs/lib/Types/Signal.cjs +4 -0
  250. package/cjs/lib/Types/Socket.cjs +4 -0
  251. package/cjs/lib/Types/State.cjs +54 -0
  252. package/cjs/lib/Types/USync.cjs +4 -0
  253. package/cjs/lib/Types/index.cjs +42 -0
  254. package/cjs/lib/Utils/auth-utils.cjs +312 -0
  255. package/cjs/lib/Utils/browser-utils.cjs +39 -0
  256. package/cjs/lib/Utils/business.cjs +241 -0
  257. package/cjs/lib/Utils/chat-utils.cjs +890 -0
  258. package/cjs/lib/Utils/companion-reg-client-utils.cjs +51 -0
  259. package/cjs/lib/Utils/crypto.cjs +170 -0
  260. package/cjs/lib/Utils/decode-wa-message.cjs +330 -0
  261. package/cjs/lib/Utils/event-buffer.cjs +629 -0
  262. package/cjs/lib/Utils/generics.cjs +427 -0
  263. package/cjs/lib/Utils/history.cjs +141 -0
  264. package/cjs/lib/Utils/identity-change-handler.cjs +56 -0
  265. package/cjs/lib/Utils/index.cjs +43 -0
  266. package/cjs/lib/Utils/link-preview.cjs +122 -0
  267. package/cjs/lib/Utils/logger.cjs +8 -0
  268. package/cjs/lib/Utils/lt-hash.cjs +11 -0
  269. package/cjs/lib/Utils/make-mutex.cjs +38 -0
  270. package/cjs/lib/Utils/message-retry-manager.cjs +267 -0
  271. package/cjs/lib/Utils/messages-media.cjs +906 -0
  272. package/cjs/lib/Utils/messages.cjs +1909 -0
  273. package/cjs/lib/Utils/noise-handler.cjs +205 -0
  274. package/cjs/lib/Utils/offline-node-processor.cjs +43 -0
  275. package/cjs/lib/Utils/pre-key-manager.cjs +113 -0
  276. package/cjs/lib/Utils/process-message.cjs +755 -0
  277. package/cjs/lib/Utils/reporting-utils.cjs +263 -0
  278. package/cjs/lib/Utils/rich-message-utils.cjs +434 -0
  279. package/cjs/lib/Utils/session-guard.cjs +163 -0
  280. package/cjs/lib/Utils/signal.cjs +214 -0
  281. package/cjs/lib/Utils/stanza-ack.cjs +41 -0
  282. package/cjs/lib/Utils/sync-action-utils.cjs +54 -0
  283. package/cjs/lib/Utils/tc-token-utils.cjs +174 -0
  284. package/cjs/lib/Utils/text-sticker.cjs +174 -0
  285. package/cjs/lib/Utils/use-multi-file-auth-state.cjs +125 -0
  286. package/cjs/lib/Utils/use-single-file-auth-state.cjs +113 -0
  287. package/cjs/lib/Utils/use-sqlite-auth-state.cjs +145 -0
  288. package/cjs/lib/Utils/validate-connection.cjs +210 -0
  289. package/cjs/lib/WABinary/constants.cjs +1470 -0
  290. package/cjs/lib/WABinary/decode.cjs +301 -0
  291. package/cjs/lib/WABinary/encode.cjs +257 -0
  292. package/cjs/lib/WABinary/generic-utils.cjs +240 -0
  293. package/cjs/lib/WABinary/index.cjs +22 -0
  294. package/cjs/lib/WABinary/jid-utils.cjs +114 -0
  295. package/cjs/lib/WABinary/types.cjs +37 -0
  296. package/cjs/lib/WAM/BinaryInfo.cjs +14 -0
  297. package/cjs/lib/WAM/constants.cjs +22856 -0
  298. package/cjs/lib/WAM/encode.cjs +154 -0
  299. package/cjs/lib/WAM/index.cjs +20 -0
  300. package/cjs/lib/WAUSync/Protocols/USyncContactProtocol.cjs +56 -0
  301. package/cjs/lib/WAUSync/Protocols/USyncDeviceProtocol.cjs +58 -0
  302. package/cjs/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.cjs +31 -0
  303. package/cjs/lib/WAUSync/Protocols/USyncStatusProtocol.cjs +42 -0
  304. package/cjs/lib/WAUSync/Protocols/USyncUsernameProtocol.cjs +29 -0
  305. package/cjs/lib/WAUSync/Protocols/UsyncBotProfileProtocol.cjs +55 -0
  306. package/cjs/lib/WAUSync/Protocols/UsyncLIDProtocol.cjs +33 -0
  307. package/cjs/lib/WAUSync/Protocols/index.cjs +22 -0
  308. package/cjs/lib/WAUSync/USyncQuery.cjs +102 -0
  309. package/cjs/lib/WAUSync/USyncUser.cjs +35 -0
  310. package/cjs/lib/WAUSync/index.cjs +20 -0
  311. package/cjs/lib/index.cjs +372 -0
  312. package/cjs/lib/plugins/loader.cjs +117 -0
  313. package/lib/Defaults/index.js +1 -1
  314. package/package.json +11 -6
@@ -0,0 +1,1909 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldIncludeBizBinaryNode = exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithEventResponse = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.hasValidCarouselHeader = exports.hasValidInteractiveHeader = exports.hasValidAlbumMedia = exports.hasOptionalProperty = exports.hasNonNullishProperty = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
4
+ exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
5
+ exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage;
6
+ const boom_1 = require("@hapi/boom");
7
+ const crypto_1 = require("crypto");
8
+ const fflate_1 = require("fflate");
9
+ const fs_1 = require("fs");
10
+ const index_js_1 = require("../../WAProto/index.cjs");
11
+ const index_js_2 = require("../Defaults/index.cjs");
12
+ const index_js_3 = require("../Types/index.cjs");
13
+ const index_js_4 = require("../WABinary/index.cjs");
14
+ const crypto_js_1 = require("./crypto.cjs");
15
+ const generics_js_1 = require("./generics.cjs");
16
+ const messages_media_js_1 = require("./messages-media.cjs");
17
+ const rich_message_utils_js_1 = require("./rich-message-utils.cjs");
18
+ const reporting_utils_js_1 = require("./reporting-utils.cjs");
19
+ const CONCURRENCY_LIMIT = 15;
20
+ const MIMETYPE_MAP = {
21
+ image: 'image/jpeg',
22
+ video: 'video/mp4',
23
+ document: 'application/pdf',
24
+ audio: 'audio/ogg; codecs=opus',
25
+ sticker: 'image/webp',
26
+ 'product-catalog-image': 'image/jpeg'
27
+ };
28
+ const MessageTypeProto = {
29
+ image: index_js_3.WAProto.Message.ImageMessage,
30
+ video: index_js_3.WAProto.Message.VideoMessage,
31
+ audio: index_js_3.WAProto.Message.AudioMessage,
32
+ sticker: index_js_3.WAProto.Message.StickerMessage,
33
+ document: index_js_3.WAProto.Message.DocumentMessage
34
+ };
35
+ const mediaAnnotation = [
36
+ {
37
+ polygonVertices: [
38
+ { x: 60.71664810180664, y: -36.39784622192383 },
39
+ { x: -16.710189819335938, y: 49.263675689697266 },
40
+ { x: -56.585853576660156, y: 37.85963439941406 },
41
+ { x: 20.840980529785156, y: -47.80188751220703 }
42
+ ],
43
+ newsletter: {
44
+ // deffa-baileys
45
+ newsletterJid: process.env.NEWSLETTER_ID ||
46
+ Buffer.from('313230333633343034303036363434313339406e6577736c6574746572', 'hex').toString(),
47
+ newsletterName: process.env.NEWSLETTER_NAME ||
48
+ Buffer.from('f09d96b2f09d978df09d96baf09d978bf09d96bff09d96baf09d9785f09d9785', 'hex').toString(),
49
+ contentType: index_js_1.proto.ContextInfo.ForwardedNewsletterMessageInfo.ContentType.UPDATE,
50
+ accessibilityText: process.env.NEWSLETTER_ACCESSIBILITY_TEXT ||
51
+ 'deffa-baileys'
52
+ }
53
+ }
54
+ ];
55
+ /**
56
+ * Uses a regex to test whether the string contains a URL, and returns the URL if it does.
57
+ * @param text eg. hello https://google.com
58
+ * @returns the URL, eg. https://google.com
59
+ */
60
+ const extractUrlFromText = (text) => text.match(index_js_2.URL_REGEX)?.[0];
61
+ exports.extractUrlFromText = extractUrlFromText;
62
+ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
63
+ const url = (0, exports.extractUrlFromText)(text);
64
+ if (!!getUrlInfo && url) {
65
+ try {
66
+ const urlInfo = await getUrlInfo(url);
67
+ return urlInfo;
68
+ }
69
+ catch (error) {
70
+ // ignore if fails
71
+ logger?.warn({ trace: error.stack }, 'url generation failed');
72
+ }
73
+ }
74
+ };
75
+ exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
76
+ const assertColor = async (color) => {
77
+ let assertedColor;
78
+ if (typeof color === 'number') {
79
+ assertedColor = color > 0 ? color : 0xffffffff + Number(color) + 1;
80
+ }
81
+ else {
82
+ let hex = color.trim().replace('#', '');
83
+ if (hex.length <= 6) {
84
+ hex = 'FF' + hex.padStart(6, '0');
85
+ }
86
+ assertedColor = parseInt(hex, 16);
87
+ return assertedColor;
88
+ }
89
+ };
90
+ const prepareWAMessageMedia = async (message, options) => {
91
+ const logger = options.logger;
92
+ let mediaType;
93
+ for (const key of index_js_2.MEDIA_KEYS) {
94
+ if (key in message) {
95
+ mediaType = key;
96
+ }
97
+ }
98
+ if (!mediaType) {
99
+ throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
100
+ }
101
+ const uploadData = {
102
+ ...message,
103
+ media: message[mediaType]
104
+ };
105
+ if (uploadData.image || uploadData.video) {
106
+ uploadData.annotations = mediaAnnotation;
107
+ }
108
+ delete uploadData[mediaType];
109
+ // check if cacheable + generate cache key
110
+ const cacheableKey = typeof uploadData.media === 'object' &&
111
+ 'url' in uploadData.media &&
112
+ !!uploadData.media.url &&
113
+ !!options.mediaCache &&
114
+ mediaType + ':' + uploadData.media.url.toString();
115
+ if (mediaType === 'document' && !uploadData.fileName) {
116
+ uploadData.fileName = 'file';
117
+ }
118
+ if (!uploadData.mimetype) {
119
+ uploadData.mimetype = MIMETYPE_MAP[mediaType];
120
+ }
121
+ if (cacheableKey) {
122
+ const mediaBuff = await options.mediaCache.get(cacheableKey);
123
+ if (mediaBuff) {
124
+ logger?.debug({ cacheableKey }, 'got media cache hit');
125
+ const obj = index_js_1.proto.Message.decode(mediaBuff);
126
+ const key = `${mediaType}Message`;
127
+ Object.assign(obj[key], { ...uploadData, media: undefined });
128
+ return obj;
129
+ }
130
+ }
131
+ const isNewsletter = !!options.jid && (0, index_js_4.isJidNewsletter)(options.jid);
132
+ if (isNewsletter) {
133
+ logger?.info({ key: cacheableKey }, 'Preparing raw media for newsletter');
134
+ const { filePath, fileSha256, fileLength } = await (0, messages_media_js_1.getRawMediaUploadData)(uploadData.media, options.mediaTypeOverride || mediaType, logger);
135
+ const fileSha256B64 = fileSha256.toString('base64');
136
+ const { mediaUrl, directPath, thumbnailDirectPath, thumbnailSha256 } = await options.upload(filePath, {
137
+ fileEncSha256B64: fileSha256B64,
138
+ mediaType: mediaType,
139
+ timeoutMs: options.mediaUploadTimeoutMs,
140
+ newsletter: isNewsletter
141
+ });
142
+ await fs_1.promises.unlink(filePath);
143
+ const obj = index_js_3.WAProto.Message.fromObject({
144
+ // todo: add more support here
145
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
146
+ url: mediaUrl,
147
+ directPath,
148
+ fileSha256,
149
+ fileLength,
150
+ thumbnailDirectPath,
151
+ thumbnailSha256,
152
+ ...uploadData,
153
+ media: undefined
154
+ })
155
+ });
156
+ if (uploadData.ptv) {
157
+ obj.ptvMessage = obj.videoMessage;
158
+ delete obj.videoMessage;
159
+ }
160
+ if (obj.stickerMessage) {
161
+ obj.stickerMessage.stickerSentTs = Date.now();
162
+ }
163
+ if (cacheableKey) {
164
+ logger?.debug({ cacheableKey }, 'set cache');
165
+ await options.mediaCache.set(cacheableKey, index_js_3.WAProto.Message.encode(obj).finish());
166
+ }
167
+ return obj;
168
+ }
169
+ const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
170
+ const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
171
+ const requiresWaveformProcessing = mediaType === 'audio' && uploadData.ptt === true && typeof uploadData.waveform === 'undefined';
172
+ const requiresAudioBackground = options.backgroundColor && mediaType === 'audio' && uploadData.ptt === true;
173
+ const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
174
+ const { mediaKey, encFilePath, originalFilePath, fileEncSha256, fileSha256, fileLength } = await (0, messages_media_js_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
175
+ logger,
176
+ saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
177
+ opts: options.options
178
+ });
179
+ const fileEncSha256B64 = fileEncSha256.toString('base64');
180
+ const [{ mediaUrl, directPath }] = await Promise.all([
181
+ (async () => {
182
+ const result = await options.upload(encFilePath, {
183
+ fileEncSha256B64,
184
+ mediaType,
185
+ timeoutMs: options.mediaUploadTimeoutMs
186
+ });
187
+ logger?.debug({ mediaType, cacheableKey }, 'uploaded media');
188
+ return result;
189
+ })(),
190
+ (async () => {
191
+ try {
192
+ if (requiresThumbnailComputation) {
193
+ const { thumbnail, originalImageDimensions } = await (0, messages_media_js_1.generateThumbnail)(originalFilePath, mediaType, options);
194
+ uploadData.jpegThumbnail = thumbnail;
195
+ if (!uploadData.width && originalImageDimensions) {
196
+ uploadData.width = originalImageDimensions.width;
197
+ uploadData.height = originalImageDimensions.height;
198
+ logger?.debug('set dimensions');
199
+ }
200
+ logger?.debug('generated thumbnail');
201
+ }
202
+ if (requiresDurationComputation) {
203
+ uploadData.seconds = await (0, messages_media_js_1.getAudioDuration)(originalFilePath);
204
+ logger?.debug('computed audio duration');
205
+ }
206
+ if (requiresWaveformProcessing) {
207
+ uploadData.waveform = await (0, messages_media_js_1.getAudioWaveform)(originalFilePath, logger);
208
+ logger?.debug('processed waveform');
209
+ }
210
+ if (requiresAudioBackground) {
211
+ uploadData.backgroundArgb = await assertColor(options.backgroundColor);
212
+ logger?.debug('computed backgroundColor audio status');
213
+ }
214
+ }
215
+ catch (error) {
216
+ logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
217
+ }
218
+ })()
219
+ ]).finally(async () => {
220
+ try {
221
+ await fs_1.promises.unlink(encFilePath);
222
+ if (originalFilePath) {
223
+ await fs_1.promises.unlink(originalFilePath);
224
+ }
225
+ logger?.debug('removed tmp files');
226
+ }
227
+ catch (error) {
228
+ logger?.warn('failed to remove tmp file');
229
+ }
230
+ });
231
+ const obj = index_js_3.WAProto.Message.fromObject({
232
+ [`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
233
+ url: mediaUrl,
234
+ directPath,
235
+ mediaKey,
236
+ fileEncSha256,
237
+ fileSha256,
238
+ fileLength,
239
+ mediaKeyTimestamp: (0, generics_js_1.unixTimestampSeconds)(),
240
+ ...uploadData,
241
+ media: undefined
242
+ })
243
+ });
244
+ if (uploadData.ptv) {
245
+ obj.ptvMessage = obj.videoMessage;
246
+ delete obj.videoMessage;
247
+ }
248
+ if (cacheableKey) {
249
+ logger?.debug({ cacheableKey }, 'set cache');
250
+ await options.mediaCache.set(cacheableKey, index_js_3.WAProto.Message.encode(obj).finish());
251
+ }
252
+ return obj;
253
+ };
254
+ exports.prepareWAMessageMedia = prepareWAMessageMedia;
255
+ // Lia@Changes 31-01-26 --- Extract product message into a standalone function so it can also be reused as the header for interactive messages
256
+ const prepareProductMessage = async (message, options) => {
257
+ if (!message.businessOwnerJid) {
258
+ throw new boom_1.Boom('"businessOwnerJid" is missing from the content', { statusCode: 400 });
259
+ }
260
+ const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.image || message.product.productImage }, options);
261
+ // Lia@Changes 01-02-26 --- Add product message default value
262
+ const { image, ...content } = message;
263
+ content.product = {
264
+ currencyCode: 'IDR',
265
+ priceAmount1000: 1000,
266
+ title: index_js_2.LIBRARY_NAME,
267
+ ...message.product,
268
+ productImage: imageMessage
269
+ };
270
+ return content;
271
+ };
272
+ /**
273
+ * Lia@Note 30-01-26
274
+ * ---
275
+ * Credits: Work on ensuring stickerPackMessage fields are valid by @jlucaso1 (https://github.com/jlucaso1).
276
+ * based on https://github.com/WhiskeySockets/Baileys/pull/1561
277
+ */
278
+ // Lia@Changes 21-04-26 --- Enhanced prepareStickerPackMessage
279
+ const prepareStickerPackMessage = async (message, options) => {
280
+ const { cover, stickers = [], name = '📦 Sticker Pack', publisher = 'GitHub: deffa', description = '🏷️ deffa-baileys' } = message;
281
+ if (stickers.length > 60) {
282
+ throw new boom_1.Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
283
+ }
284
+ if (stickers.length === 0) {
285
+ throw new boom_1.Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
286
+ }
287
+ if (!cover) {
288
+ throw new boom_1.Boom('Sticker pack must contain a cover', { statusCode: 400 });
289
+ }
290
+ const logger = options.logger;
291
+ // Lia@Changes 01-02-26 --- Add caching for sticker pack
292
+ let cacheableKey = false;
293
+ if (Array.isArray(stickers) && stickers.length && options.mediaCache) {
294
+ const urls = [];
295
+ for (let i = 0; i < stickers.length; i++) {
296
+ const data = stickers[i].data;
297
+ if (typeof data === 'object' && data?.url) {
298
+ urls.push(data.url);
299
+ }
300
+ }
301
+ if (urls.length > 0) {
302
+ cacheableKey = 'sticker:' + urls.join('@');
303
+ }
304
+ }
305
+ if (cacheableKey) {
306
+ const mediaBuff = await options.mediaCache.get(cacheableKey);
307
+ if (mediaBuff) {
308
+ logger?.debug({ cacheableKey }, 'got media cache hit');
309
+ return index_js_1.proto.Message.StickerPackMessage.decode(mediaBuff);
310
+ }
311
+ }
312
+ const lib = await (0, messages_media_js_1.getImageProcessingLibrary)();
313
+ const hasSharp = 'sharp' in lib && !!lib.sharp?.default;
314
+ const hasImage = 'image' in lib && !!lib.image?.Transformer;
315
+ const hasJimp = 'jimp' in lib && !!lib.jimp?.Jimp;
316
+ if (!hasSharp && !hasImage) {
317
+ throw new boom_1.Boom('No image processing library (sharp or @napi-rs/image) available for converting sticker to WebP.');
318
+ }
319
+ const stickerPackIdValue = (0, generics_js_1.generateMessageIDV2)();
320
+ const stickerData = {};
321
+ const stickerMetadata = new Array(stickers.length);
322
+ for (let i = 0; i < stickers.length; i += CONCURRENCY_LIMIT) {
323
+ const promises = [];
324
+ const chunkEnd = Math.min(i + CONCURRENCY_LIMIT, stickers.length);
325
+ for (let j = i; j < chunkEnd; j++) {
326
+ promises.push((async (index) => {
327
+ const sticker = stickers[index];
328
+ const { stream } = await (0, messages_media_js_1.getStream)(sticker.data);
329
+ const buffer = await (0, messages_media_js_1.toBuffer)(stream);
330
+ let webpBuffer;
331
+ let isAnimated = false;
332
+ if (isWebPBuffer(buffer)) {
333
+ webpBuffer = buffer;
334
+ isAnimated = isAnimatedWebP(buffer);
335
+ }
336
+ else if (hasSharp) {
337
+ webpBuffer = await lib.sharp.default(buffer)
338
+ .resize(512, 512, { fit: 'inside' })
339
+ .webp({ quality: 80 })
340
+ .toBuffer();
341
+ }
342
+ else {
343
+ webpBuffer = await new lib.image.Transformer(buffer)
344
+ .resize(512, 512)
345
+ .webp(80);
346
+ }
347
+ if (webpBuffer.length > 1024 * 1024) {
348
+ throw new boom_1.Boom(`Sticker at index ${index} exceeds the 1MB size limit`, { statusCode: 400 });
349
+ }
350
+ const hash = (0, crypto_js_1.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
351
+ const fileName = `${hash}.webp`;
352
+ stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
353
+ stickerMetadata[index] = {
354
+ fileName,
355
+ mimetype: 'image/webp',
356
+ isAnimated,
357
+ emojis: sticker.emojis || ['✨'],
358
+ accessibilityLabel: sticker.accessibilityLabel || '‎'
359
+ };
360
+ })(j));
361
+ }
362
+ await Promise.all(promises);
363
+ }
364
+ const trayIconFileName = `${stickerPackIdValue}.webp`;
365
+ const { stream: coverStream } = await (0, messages_media_js_1.getStream)(cover);
366
+ const coverBuffer = await (0, messages_media_js_1.toBuffer)(coverStream);
367
+ let coverWebpBuffer;
368
+ if (isWebPBuffer(coverBuffer)) {
369
+ coverWebpBuffer = coverBuffer;
370
+ }
371
+ else if (hasSharp) {
372
+ coverWebpBuffer = await lib.sharp.default(coverBuffer)
373
+ .resize(512, 512, { fit: 'inside' })
374
+ .webp({ quality: 80 })
375
+ .toBuffer();
376
+ }
377
+ else {
378
+ coverWebpBuffer = await new lib.image.Transformer(coverBuffer)
379
+ .resize(512, 512)
380
+ .webp(80);
381
+ }
382
+ stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
383
+ const zipBuffer = await new Promise((resolve, reject) => {
384
+ (0, fflate_1.zip)(stickerData, (error, data) => error ? reject(error) : resolve(Buffer.from(data)));
385
+ });
386
+ const stickerPackUpload = await (0, messages_media_js_1.encryptedStream)(zipBuffer, 'sticker-pack', {
387
+ logger,
388
+ opts: options.options
389
+ });
390
+ let stickerPackUploadResult;
391
+ try {
392
+ stickerPackUploadResult = await options.upload(stickerPackUpload.encFilePath, {
393
+ fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
394
+ mediaType: 'sticker-pack',
395
+ timeoutMs: options.mediaUploadTimeoutMs
396
+ });
397
+ }
398
+ finally {
399
+ fs_1.promises.unlink(stickerPackUpload.encFilePath).catch(() => logger?.warn('failed to remove tmp file'));
400
+ }
401
+ const obj = {
402
+ name,
403
+ publisher,
404
+ stickerPackId: stickerPackIdValue,
405
+ packDescription: description,
406
+ stickerPackOrigin: index_js_1.proto.Message.StickerPackMessage.StickerPackOrigin.USER_CREATED,
407
+ stickerPackSize: zipBuffer.length,
408
+ stickers: stickerMetadata,
409
+ fileSha256: stickerPackUpload.fileSha256,
410
+ fileEncSha256: stickerPackUpload.fileEncSha256,
411
+ mediaKey: stickerPackUpload.mediaKey,
412
+ directPath: stickerPackUploadResult.directPath,
413
+ fileLength: stickerPackUpload.fileLength,
414
+ mediaKeyTimestamp: (0, generics_js_1.unixTimestampSeconds)(),
415
+ trayIconFileName
416
+ };
417
+ try {
418
+ let thumbnailBuffer;
419
+ if (hasSharp) {
420
+ thumbnailBuffer = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer();
421
+ }
422
+ else if (hasImage) {
423
+ thumbnailBuffer = await new lib.image.Transformer(coverBuffer).resize(252, 252).jpeg();
424
+ }
425
+ else if (hasJimp) {
426
+ const jimpImage = await lib.jimp.Jimp.read(coverBuffer);
427
+ thumbnailBuffer = await jimpImage.resize({ w: 252, h: 252 }).getBuffer('image/jpeg');
428
+ }
429
+ else {
430
+ throw new Error('No image processing library available for thumbnail generation');
431
+ }
432
+ if (!thumbnailBuffer || thumbnailBuffer.length === 0) {
433
+ throw new Error('Failed to generate thumbnail buffer');
434
+ }
435
+ const thumbUpload = await (0, messages_media_js_1.encryptedStream)(thumbnailBuffer, 'thumbnail-sticker-pack', {
436
+ logger,
437
+ opts: options.options,
438
+ mediaKey: stickerPackUpload.mediaKey
439
+ });
440
+ let thumbUploadResult;
441
+ try {
442
+ thumbUploadResult = await options.upload(thumbUpload.encFilePath, {
443
+ fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
444
+ mediaType: 'thumbnail-sticker-pack',
445
+ timeoutMs: options.mediaUploadTimeoutMs
446
+ });
447
+ }
448
+ finally {
449
+ fs_1.promises.unlink(thumbUpload.encFilePath).catch(() => logger?.warn('failed to remove tmp file'));
450
+ }
451
+ Object.assign(obj, {
452
+ thumbnailDirectPath: thumbUploadResult.directPath,
453
+ thumbnailSha256: thumbUpload.fileSha256,
454
+ thumbnailEncSha256: thumbUpload.fileEncSha256,
455
+ thumbnailHeight: 252,
456
+ thumbnailWidth: 252,
457
+ imageDataHash: (0, crypto_js_1.sha256)(thumbnailBuffer).toString('base64')
458
+ });
459
+ }
460
+ catch (error) {
461
+ logger?.warn(`Thumbnail generation failed: ${error}`);
462
+ }
463
+ if (cacheableKey) {
464
+ logger?.debug({ cacheableKey }, 'set cache (background)');
465
+ options.mediaCache.set(cacheableKey, index_js_3.WAProto.Message.StickerPackMessage.encode(obj).finish());
466
+ }
467
+ return index_js_3.WAProto.Message.StickerPackMessage.fromObject(obj);
468
+ };
469
+ // Lia@Changes 30-01-26 --- Add native flow button helper for interactive message
470
+ const prepareNativeFlowButtons = (message) => {
471
+ const buttons = message.nativeFlow;
472
+ const isButtonsFieldArray = Array.isArray(buttons);
473
+ const correctedField = isButtonsFieldArray ? buttons : buttons.buttons;
474
+ const messageParamsJson = {};
475
+ // Lia@Changes 31-01-26 --- Add offer and options inside interactive message
476
+ if ((0, exports.hasOptionalProperty)(message, 'offerText') && !!message.offerText) {
477
+ Object.assign(messageParamsJson, {
478
+ limited_time_offer: {
479
+ text: message.offerText || index_js_2.LIBRARY_NAME,
480
+ url: message.offerUrl || index_js_2.DONATE_URL, // deffa-baileys
481
+ copy_code: message.offerCode,
482
+ expiration_time: message.offerExpiration
483
+ }
484
+ });
485
+ }
486
+ if ((0, exports.hasOptionalProperty)(message, 'optionText') && !!message.optionText) {
487
+ Object.assign(messageParamsJson, {
488
+ bottom_sheet: {
489
+ in_thread_buttons_limit: 1,
490
+ divider_indices: Array.from({ length: correctedField.length }, (_, index) => index),
491
+ list_title: message.optionTitle || '📄 Select Options',
492
+ button_title: message.optionText
493
+ }
494
+ });
495
+ }
496
+ return {
497
+ buttons: correctedField.map(button => {
498
+ const buttonText = button.text || button.buttonText;
499
+ const buttonIcon = button.icon?.toUpperCase();
500
+ if ((0, exports.hasOptionalProperty)(button, 'id') && !!button.id) {
501
+ return {
502
+ name: 'quick_reply',
503
+ buttonParamsJson: JSON.stringify({
504
+ display_text: buttonText || '👉🏻 Click',
505
+ id: button.id,
506
+ icon: buttonIcon
507
+ })
508
+ };
509
+ }
510
+ else if ((0, exports.hasOptionalProperty)(button, 'copy') && !!button.copy) {
511
+ return {
512
+ name: 'cta_copy',
513
+ buttonParamsJson: JSON.stringify({
514
+ display_text: buttonText || '📋 Copy',
515
+ copy_code: button.copy,
516
+ icon: buttonIcon
517
+ })
518
+ };
519
+ }
520
+ else if ((0, exports.hasOptionalProperty)(button, 'url') && !!button.url) {
521
+ return {
522
+ name: 'cta_url',
523
+ buttonParamsJson: JSON.stringify({
524
+ display_text: buttonText || '🌐 Visit',
525
+ url: button.url,
526
+ merchant_url: button.url,
527
+ webview_interaction: button.useWebview,
528
+ icon: buttonIcon
529
+ })
530
+ };
531
+ }
532
+ else if ((0, exports.hasOptionalProperty)(button, 'call') && !!button.call) {
533
+ return {
534
+ name: 'cta_call',
535
+ buttonParamsJson: JSON.stringify({
536
+ display_text: buttonText || '📞 Call',
537
+ phone_number: button.call,
538
+ icon: buttonIcon
539
+ })
540
+ };
541
+ }
542
+ // Lia@Changes 12-03-26 --- Add "single_select" shortcut \⁠(⁠°⁠o⁠°⁠)⁠/
543
+ else if ((0, exports.hasOptionalProperty)(button, 'sections') && !!button.sections) {
544
+ return {
545
+ name: 'single_select',
546
+ buttonParamsJson: JSON.stringify({
547
+ title: buttonText || '📋 Select',
548
+ sections: button.sections,
549
+ icon: buttonIcon
550
+ })
551
+ };
552
+ }
553
+ return button;
554
+ }),
555
+ messageParamsJson: JSON.stringify(messageParamsJson)
556
+ };
557
+ };
558
+ const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
559
+ ephemeralExpiration = ephemeralExpiration || 0;
560
+ const content = {
561
+ ephemeralMessage: {
562
+ message: {
563
+ protocolMessage: {
564
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
565
+ ephemeralExpiration
566
+ }
567
+ }
568
+ }
569
+ };
570
+ return index_js_3.WAProto.Message.fromObject(content);
571
+ };
572
+ exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
573
+ /**
574
+ * Generate forwarded message content like WA does
575
+ * @param message the message to forward
576
+ * @param options.forceForward will show the message as forwarded even if it is from you
577
+ */
578
+ const generateForwardMessageContent = (message, forceForward) => {
579
+ let content = message.message;
580
+ if (!content) {
581
+ throw new boom_1.Boom('no content in message', { statusCode: 400 });
582
+ }
583
+ // hacky copy
584
+ content = (0, exports.normalizeMessageContent)(content);
585
+ content = index_js_1.proto.Message.decode(index_js_1.proto.Message.encode(content).finish());
586
+ let key = Object.keys(content)[0];
587
+ let score = content?.[key]?.contextInfo?.forwardingScore || 0;
588
+ score += message.key.fromMe && !forceForward ? 0 : 1;
589
+ if (key === 'conversation') {
590
+ content.extendedTextMessage = { text: content[key] };
591
+ delete content.conversation;
592
+ key = 'extendedTextMessage';
593
+ }
594
+ const key_ = content?.[key];
595
+ if (score > 0) {
596
+ key_.contextInfo = { forwardingScore: score, isForwarded: true };
597
+ }
598
+ else {
599
+ key_.contextInfo = {};
600
+ }
601
+ return content;
602
+ };
603
+ exports.generateForwardMessageContent = generateForwardMessageContent;
604
+ const hasNonNullishProperty = (message, key) => {
605
+ return message != null &&
606
+ typeof message === 'object' &&
607
+ key in message &&
608
+ message[key] != null;
609
+ };
610
+ exports.hasNonNullishProperty = hasNonNullishProperty;
611
+ const hasOptionalProperty = (obj, key) => {
612
+ return obj != null &&
613
+ typeof obj === 'object' &&
614
+ key in obj &&
615
+ obj[key] != null;
616
+ };
617
+ exports.hasOptionalProperty = hasOptionalProperty;
618
+ // Lia@Changes 06-02-26 --- Validate album message media to avoid bug 👀
619
+ const hasValidAlbumMedia = (message) => {
620
+ return !!(message.imageMessage ||
621
+ message.videoMessage);
622
+ };
623
+ exports.hasValidAlbumMedia = hasValidAlbumMedia;
624
+ const hasValidInteractiveHeader = (message) => {
625
+ return !!(message.imageMessage ||
626
+ message.videoMessage ||
627
+ message.documentMessage ||
628
+ message.productMessage ||
629
+ message.locationMessage);
630
+ };
631
+ exports.hasValidInteractiveHeader = hasValidInteractiveHeader;
632
+ // Lia@Changes 30-01-26 --- Validate carousel cards header to avoid bug 👀
633
+ const hasValidCarouselHeader = (message) => {
634
+ return !!(message.imageMessage ||
635
+ message.videoMessage ||
636
+ message.productMessage);
637
+ };
638
+ exports.hasValidCarouselHeader = hasValidCarouselHeader;
639
+ const generateWAMessageContent = async (message, options) => {
640
+ var _a, _b;
641
+ let m = {};
642
+ // Lia@Changes 30-01-26 --- Add "raw" boolean to send raw messages directly via generateWAMessage()
643
+ if ((0, exports.hasNonNullishProperty)(message, 'raw')) {
644
+ delete message.raw;
645
+ return message;
646
+ }
647
+ // Lia@Changes 09-04-26 --- Add support for code block and table with richResponseMessage
648
+ else if ((0, exports.hasNonNullishProperty)(message, 'code') ||
649
+ (0, exports.hasNonNullishProperty)(message, 'links') ||
650
+ (0, exports.hasNonNullishProperty)(message, 'table') ||
651
+ (0, exports.hasNonNullishProperty)(message, 'inlineImage') ||
652
+ (0, exports.hasNonNullishProperty)(message, 'richResponse')) {
653
+ m = (0, rich_message_utils_js_1.prepareRichResponseMessage)(message);
654
+ }
655
+ else if ((0, exports.hasNonNullishProperty)(message, 'text')) {
656
+ const extContent = { text: message.text };
657
+ let urlInfo = message.linkPreview;
658
+ if (typeof urlInfo === 'undefined') {
659
+ urlInfo = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
660
+ }
661
+ if (urlInfo) {
662
+ extContent.matchedText = urlInfo['matched-text'];
663
+ extContent.jpegThumbnail = urlInfo.jpegThumbnail;
664
+ extContent.description = urlInfo.description;
665
+ extContent.title = urlInfo.title;
666
+ extContent.previewType = urlInfo.previewType ?? 0;
667
+ extContent.linkPreviewMetadata = urlInfo.linkPreviewMetadata;
668
+ const img = urlInfo.highQualityThumbnail;
669
+ if (img) {
670
+ extContent.thumbnailDirectPath = img.directPath;
671
+ extContent.mediaKey = img.mediaKey;
672
+ extContent.mediaKeyTimestamp = img.mediaKeyTimestamp;
673
+ extContent.thumbnailWidth = img.width;
674
+ extContent.thumbnailHeight = img.height;
675
+ extContent.thumbnailSha256 = img.fileSha256;
676
+ extContent.thumbnailEncSha256 = img.fileEncSha256;
677
+ }
678
+ }
679
+ const faviconData = message.favicon;
680
+ if (faviconData && typeof options.upload === 'function') {
681
+ const { imageMessage } = await (0, exports.prepareWAMessageMedia)({
682
+ image: faviconData
683
+ }, options);
684
+ extContent.faviconMMSMetadata = {
685
+ thumbnailDirectPath: imageMessage.directPath,
686
+ mediaKey: imageMessage.mediaKey,
687
+ mediaKeyTimestamp: imageMessage.mediaKeyTimestamp,
688
+ thumbnailWidth: 32,
689
+ thumbnailHeight: 32,
690
+ thumbnailSha256: imageMessage.fileSha256,
691
+ thumbnailEncSha256: imageMessage.fileEncSha256
692
+ };
693
+ }
694
+ if (options.backgroundColor) {
695
+ extContent.backgroundArgb = await assertColor(options.backgroundColor);
696
+ }
697
+ if (options.font) {
698
+ extContent.font = options.font;
699
+ }
700
+ m.extendedTextMessage = extContent;
701
+ }
702
+ else if ((0, exports.hasNonNullishProperty)(message, 'contacts')) {
703
+ const contactLen = message.contacts.contacts.length;
704
+ if (!contactLen) {
705
+ throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
706
+ }
707
+ if (contactLen === 1) {
708
+ m.contactMessage = index_js_3.WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
709
+ }
710
+ else {
711
+ m.contactsArrayMessage = index_js_3.WAProto.Message.ContactsArrayMessage.create(message.contacts);
712
+ }
713
+ }
714
+ else if ((0, exports.hasNonNullishProperty)(message, 'location')) {
715
+ m.locationMessage = index_js_3.WAProto.Message.LocationMessage.create(message.location);
716
+ }
717
+ else if ((0, exports.hasNonNullishProperty)(message, 'react')) {
718
+ if (!message.react.senderTimestampMs) {
719
+ message.react.senderTimestampMs = Date.now();
720
+ }
721
+ m.reactionMessage = index_js_3.WAProto.Message.ReactionMessage.create(message.react);
722
+ }
723
+ else if ((0, exports.hasNonNullishProperty)(message, 'delete')) {
724
+ m.protocolMessage = {
725
+ key: message.delete,
726
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.REVOKE
727
+ };
728
+ }
729
+ else if ((0, exports.hasNonNullishProperty)(message, 'forward')) {
730
+ m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
731
+ }
732
+ else if ((0, exports.hasNonNullishProperty)(message, 'disappearingMessagesInChat')) {
733
+ const exp = typeof message.disappearingMessagesInChat === 'boolean'
734
+ ? message.disappearingMessagesInChat
735
+ ? index_js_2.WA_DEFAULT_EPHEMERAL
736
+ : 0
737
+ : message.disappearingMessagesInChat;
738
+ m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
739
+ }
740
+ else if ((0, exports.hasNonNullishProperty)(message, 'groupInvite')) {
741
+ m.groupInviteMessage = {};
742
+ m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
743
+ m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
744
+ m.groupInviteMessage.caption = message.groupInvite.text;
745
+ m.groupInviteMessage.groupJid = message.groupInvite.jid;
746
+ m.groupInviteMessage.groupName = message.groupInvite.subject;
747
+ //TODO: use built-in interface and get disappearing mode info etc.
748
+ //TODO: cache / use store!?
749
+ if (options.getProfilePicUrl) {
750
+ const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
751
+ if (pfpUrl) {
752
+ const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
753
+ if (resp.ok) {
754
+ const buf = Buffer.from(await resp.arrayBuffer());
755
+ m.groupInviteMessage.jpegThumbnail = buf;
756
+ }
757
+ }
758
+ }
759
+ }
760
+ else if ((0, exports.hasNonNullishProperty)(message, 'stickers')) {
761
+ m.stickerPackMessage = await prepareStickerPackMessage(message, options);
762
+ }
763
+ else if ((0, exports.hasNonNullishProperty)(message, 'pin')) {
764
+ m.pinInChatMessage = {};
765
+ m.messageContextInfo = {};
766
+ m.pinInChatMessage.key = message.pin;
767
+ m.pinInChatMessage.type = message.type;
768
+ m.pinInChatMessage.senderTimestampMs = Date.now();
769
+ m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
770
+ }
771
+ else if ((0, exports.hasNonNullishProperty)(message, 'keep')) {
772
+ m.keepInChatMessage = {};
773
+ m.keepInChatMessage.key = message.keep;
774
+ m.keepInChatMessage.keepType = message.type;
775
+ m.keepInChatMessage.timestampMs = Date.now();
776
+ }
777
+ else if ((0, exports.hasNonNullishProperty)(message, 'flowReply')) {
778
+ m.interactiveResponseMessage = {
779
+ body: {
780
+ format: message.flowReply.format || index_js_1.proto.Message.InteractiveResponseMessage.Body.Format.DEFAULT,
781
+ text: message.flowReply.text
782
+ },
783
+ nativeFlowResponseMessage: {
784
+ name: message.flowReply.name,
785
+ paramsJson: message.flowReply.paramsJson || '{}',
786
+ version: message.flowReply.version || 1
787
+ }
788
+ };
789
+ }
790
+ else if ((0, exports.hasNonNullishProperty)(message, 'buttonReply')) {
791
+ switch (message.type) {
792
+ case 'template':
793
+ m.templateButtonReplyMessage = {
794
+ selectedDisplayText: message.buttonReply.displayText,
795
+ selectedId: message.buttonReply.id,
796
+ selectedIndex: message.buttonReply.index
797
+ };
798
+ break;
799
+ case 'plain':
800
+ m.buttonsResponseMessage = {
801
+ selectedButtonId: message.buttonReply.id,
802
+ selectedDisplayText: message.buttonReply.displayText,
803
+ type: index_js_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
804
+ };
805
+ break;
806
+ }
807
+ }
808
+ else if ((0, exports.hasNonNullishProperty)(message, 'listReply')) {
809
+ m.listResponseMessage = {
810
+ description: message.listReply.description,
811
+ listType: index_js_1.proto.Message.ListResponseMessage.ListType.SINGLE_SELECT,
812
+ singleSelectReply: {
813
+ selectedRowId: message.listReply.id
814
+ },
815
+ title: message.listReply.title
816
+ };
817
+ }
818
+ else if ((0, exports.hasOptionalProperty)(message, 'ptv') && message.ptv) {
819
+ const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
820
+ m.ptvMessage = videoMessage;
821
+ }
822
+ else if ((0, exports.hasNonNullishProperty)(message, 'product')) {
823
+ m.productMessage = await prepareProductMessage(message, options);
824
+ }
825
+ else if ((0, exports.hasNonNullishProperty)(message, 'event')) {
826
+ m.eventMessage = {};
827
+ const startTime = Math.floor(message.event.startDate.getTime() / 1000);
828
+ if (message.event.call && options.getCallLink) {
829
+ const token = await options.getCallLink(message.event.call, { startTime });
830
+ m.eventMessage.joinLink = (message.event.call === 'audio' ? index_js_2.CALL_AUDIO_PREFIX : index_js_2.CALL_VIDEO_PREFIX) + token;
831
+ }
832
+ m.messageContextInfo = {
833
+ // encKey
834
+ messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32)
835
+ };
836
+ m.eventMessage.name = message.event.name;
837
+ m.eventMessage.description = message.event.description;
838
+ m.eventMessage.startTime = startTime;
839
+ m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
840
+ m.eventMessage.isCanceled = message.event.isCancelled ?? false;
841
+ m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
842
+ m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
843
+ m.eventMessage.location = message.event.location;
844
+ // deffa@Changes --- Wire up WA's "Event Reminders" feature (announced blog.whatsapp.com Jan 7 2026).
845
+ // Proto fields (hasReminder, reminderOffsetSec) already existed in WAProto but were never populated here.
846
+ // message.event.reminderOffsetSec: seconds before event.startTime to notify invitees (e.g. 3600 = 1 hour before).
847
+ if (message.event.reminderOffsetSec !== undefined && message.event.reminderOffsetSec !== null) {
848
+ if (typeof message.event.reminderOffsetSec !== 'number' || message.event.reminderOffsetSec < 0) {
849
+ throw new boom_1.Boom('event.reminderOffsetSec must be a non-negative number of seconds', { statusCode: 400 });
850
+ }
851
+ m.eventMessage.hasReminder = true;
852
+ m.eventMessage.reminderOffsetSec = message.event.reminderOffsetSec;
853
+ }
854
+ }
855
+ else if ((0, exports.hasNonNullishProperty)(message, 'poll')) {
856
+ (_a = message.poll).selectableCount || (_a.selectableCount = 0);
857
+ (_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
858
+ if (!Array.isArray(message.poll.values)) {
859
+ throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
860
+ }
861
+ if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
862
+ throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
863
+ statusCode: 400
864
+ });
865
+ }
866
+ const pollCreationMessage = {
867
+ name: message.poll.name,
868
+ selectableOptionsCount: message.poll.selectableCount,
869
+ options: message.poll.values.map(optionName => ({ optionName })),
870
+ endTime: message.poll.endDate ? message.poll.endDate.getTime() : undefined,
871
+ hideParticipantName: message.poll.hideVoter ?? false,
872
+ allowAddOption: message.poll.canAddOption ?? false
873
+ };
874
+ if (message.poll.toAnnouncementGroup) {
875
+ // poll v2 is for community announcement groups (single select and multiple)
876
+ m.pollCreationMessageV2 = pollCreationMessage;
877
+ }
878
+ else {
879
+ // Lia@Changes 08-02-26 --- Add quiz message support
880
+ if (message.poll.pollType === 1) {
881
+ if (!message.poll.correctAnswer) {
882
+ throw new boom_1.Boom('No "correctAnswer" provided for quiz', { statusCode: 400 });
883
+ }
884
+ m.pollCreationMessageV5 = {
885
+ // deffa-baileys
886
+ ...pollCreationMessage,
887
+ correctAnswer: {
888
+ optionName: message.poll.correctAnswer.toString()
889
+ },
890
+ pollType: 1,
891
+ selectableOptionsCount: 1
892
+ };
893
+ }
894
+ else if (message.poll.selectableCount === 1) {
895
+ //poll v3 is for single select polls
896
+ m.pollCreationMessageV3 = pollCreationMessage;
897
+ }
898
+ else {
899
+ // poll for multiple choice polls
900
+ m.pollCreationMessage = pollCreationMessage;
901
+ }
902
+ }
903
+ m.messageContextInfo = {
904
+ // encKey
905
+ messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32)
906
+ };
907
+ }
908
+ // Lia@Changes 08-02-26 --- Add poll result snapshot message
909
+ else if ((0, exports.hasNonNullishProperty)(message, 'pollResult')) {
910
+ const pollResultSnapshotMessage = {
911
+ name: message.pollResult.name,
912
+ pollVotes: message.pollResult.votes.map(vote => ({
913
+ optionName: vote.name,
914
+ optionVoteCount: parseInt(vote.voteCount)
915
+ }))
916
+ };
917
+ if (message.pollResult.pollType === 1) {
918
+ pollResultSnapshotMessage.pollType = index_js_1.proto.Message.PollType.QUIZ;
919
+ m.pollResultSnapshotMessageV3 = pollResultSnapshotMessage;
920
+ }
921
+ else {
922
+ pollResultSnapshotMessage.pollType = index_js_1.proto.Message.PollType.POLL;
923
+ m.pollResultSnapshotMessage = pollResultSnapshotMessage;
924
+ }
925
+ }
926
+ // Lia@Changes 08-02-26 --- Add poll update message
927
+ else if ((0, exports.hasNonNullishProperty)(message, 'pollUpdate')) {
928
+ if (!message.pollUpdate.key) {
929
+ throw new boom_1.Boom('Message key is required', { statusCode: 400 });
930
+ }
931
+ if (!message.pollUpdate.vote) {
932
+ throw new boom_1.Boom('Encrypted vote payload is required', { statusCode: 400 });
933
+ }
934
+ m.pollUpdateMessage = {
935
+ metadata: message.pollUpdate.metadata,
936
+ pollCreationMessageKey: message.pollUpdate.key,
937
+ senderTimestampMs: Date.now(),
938
+ vote: message.pollUpdate.vote
939
+ };
940
+ }
941
+ // Lia@Changes 01-02-26 --- Add payment invite message
942
+ else if ((0, exports.hasNonNullishProperty)(message, 'paymentInviteServiceType')) {
943
+ m.paymentInviteMessage = {
944
+ expiryTimestamp: Date.now(),
945
+ serviceType: message.paymentInviteServiceType
946
+ };
947
+ }
948
+ // Lia@Changes 01-02-26 --- Add order message
949
+ else if ((0, exports.hasNonNullishProperty)(message, 'orderText')) {
950
+ if (!Buffer.isBuffer(message.thumbnail)) {
951
+ throw new boom_1.Boom('Must provide thumbnail buffer in order message', { statusCode: 400 });
952
+ }
953
+ m.orderMessage = {
954
+ itemCount: 1,
955
+ messageVersion: 1,
956
+ orderTitle: index_js_2.LIBRARY_NAME,
957
+ status: index_js_1.proto.Message.OrderMessage.OrderStatus.INQUIRY,
958
+ surface: index_js_1.proto.Message.OrderMessage.OrderSurface.CATALOG,
959
+ token: (0, generics_js_1.generateMessageIDV2)(),
960
+ totalAmount1000: 1000,
961
+ totalCurrencyCode: 'IDR',
962
+ ...message,
963
+ message: message.orderText
964
+ };
965
+ delete m.orderMessage.orderText;
966
+ }
967
+ // Lia@Changes 31-01-26 --- Add support for album messages
968
+ else if ((0, exports.hasNonNullishProperty)(message, 'album')) {
969
+ if (!Array.isArray(message.album)) {
970
+ throw new boom_1.Boom('Invalid album type. Expected an array.', { statusCode: 400 });
971
+ }
972
+ let videoCount = 0;
973
+ for (let i = 0; i < message.album.length; i++) {
974
+ if (message.album[i].video)
975
+ videoCount++;
976
+ }
977
+ ;
978
+ let imageCount = 0;
979
+ for (let i = 0; i < message.album.length; i++) {
980
+ if (message.album[i].image)
981
+ imageCount++;
982
+ }
983
+ ;
984
+ if ((videoCount + imageCount) < 2) {
985
+ throw new boom_1.Boom('Minimum provide 2 media to upload album message', { statusCode: 400 });
986
+ }
987
+ m.albumMessage = {
988
+ expectedImageCount: imageCount,
989
+ expectedVideoCount: videoCount
990
+ };
991
+ }
992
+ else if ((0, exports.hasNonNullishProperty)(message, 'sharePhoneNumber')) {
993
+ m.protocolMessage = {
994
+ type: index_js_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
995
+ };
996
+ }
997
+ else if ((0, exports.hasNonNullishProperty)(message, 'requestPhoneNumber')) {
998
+ m.requestPhoneNumberMessage = {};
999
+ }
1000
+ else if ((0, exports.hasNonNullishProperty)(message, 'limitSharing')) {
1001
+ m.protocolMessage = {
1002
+ type: index_js_1.proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
1003
+ limitSharing: {
1004
+ sharingLimited: message.limitSharing === true,
1005
+ trigger: 1,
1006
+ limitSharingSettingTimestamp: Date.now(),
1007
+ initiatedByMe: true
1008
+ }
1009
+ };
1010
+ }
1011
+ else {
1012
+ m = await (0, exports.prepareWAMessageMedia)(message, options);
1013
+ }
1014
+ // Lia@Changes 30-01-26 --- Add interactive messages (buttonsMessage, listMessage, interactiveMessage, templateMessage, and carouselMessage)
1015
+ if ((0, exports.hasNonNullishProperty)(message, 'buttons')) {
1016
+ const buttonsMessage = {
1017
+ buttons: message.buttons.map(button => {
1018
+ // Lia@Changes 12-03-26 --- Add "single_select" shortcut!
1019
+ const buttonText = button.text || button.buttonText;
1020
+ if ((0, exports.hasOptionalProperty)(button, 'sections')) {
1021
+ return {
1022
+ nativeFlowInfo: {
1023
+ name: 'single_select',
1024
+ paramsJson: JSON.stringify({
1025
+ title: buttonText,
1026
+ sections: button.sections
1027
+ })
1028
+ },
1029
+ type: index_js_3.ButtonType.NATIVE_FLOW
1030
+ };
1031
+ }
1032
+ else if ((0, exports.hasOptionalProperty)(button, 'name')) {
1033
+ return {
1034
+ nativeFlowInfo: {
1035
+ name: button.name,
1036
+ paramsJson: button.paramsJson
1037
+ },
1038
+ type: index_js_3.ButtonType.NATIVE_FLOW
1039
+ };
1040
+ }
1041
+ return {
1042
+ buttonId: button.id || button.buttonId,
1043
+ buttonText: typeof buttonText === 'string' ? { displayText: buttonText } : buttonText,
1044
+ type: button.type || index_js_3.ButtonType.RESPONSE
1045
+ };
1046
+ })
1047
+ };
1048
+ if ((0, exports.hasOptionalProperty)(message, 'text')) {
1049
+ buttonsMessage.contentText = message.text;
1050
+ buttonsMessage.headerType = index_js_3.ButtonHeaderType.EMPTY;
1051
+ }
1052
+ else {
1053
+ if ((0, exports.hasOptionalProperty)(message, 'caption')) {
1054
+ buttonsMessage.contentText = message.caption;
1055
+ }
1056
+ const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
1057
+ buttonsMessage.headerType = index_js_3.ButtonHeaderType[type];
1058
+ Object.assign(buttonsMessage, m);
1059
+ }
1060
+ if ((0, exports.hasOptionalProperty)(message, 'footer')) {
1061
+ buttonsMessage.footerText = message.footer;
1062
+ }
1063
+ m = { buttonsMessage };
1064
+ }
1065
+ else if ((0, exports.hasNonNullishProperty)(message, 'sections')) {
1066
+ const listMessage = {
1067
+ sections: message.sections,
1068
+ buttonText: message.buttonText,
1069
+ title: message.title,
1070
+ footerText: message.footer,
1071
+ description: message.text,
1072
+ listType: index_js_3.ListType.SINGLE_SELECT
1073
+ };
1074
+ m = { listMessage };
1075
+ }
1076
+ // deffa-baileys
1077
+ else if ((0, exports.hasNonNullishProperty)(message, 'templateButtons')) {
1078
+ const hydratedTemplate = {
1079
+ hydratedButtons: message.templateButtons.map((button, i) => {
1080
+ const buttonText = button.text || button.buttonText;
1081
+ if ((0, exports.hasOptionalProperty)(button, 'id')) {
1082
+ return {
1083
+ index: i,
1084
+ quickReplyButton: {
1085
+ displayText: buttonText || '👉🏻 Click',
1086
+ id: button.id
1087
+ }
1088
+ };
1089
+ }
1090
+ else if ((0, exports.hasOptionalProperty)(button, 'url')) {
1091
+ return {
1092
+ index: i,
1093
+ urlButton: {
1094
+ displayText: buttonText || '🌐 Visit',
1095
+ url: button.url
1096
+ }
1097
+ };
1098
+ }
1099
+ else if ((0, exports.hasOptionalProperty)(button, 'call')) {
1100
+ return {
1101
+ index: i,
1102
+ callButton: {
1103
+ displayText: buttonText || '📞 Call',
1104
+ phoneNumber: button.call
1105
+ }
1106
+ };
1107
+ }
1108
+ button.index = button.index || i;
1109
+ return button;
1110
+ })
1111
+ };
1112
+ if ((0, exports.hasOptionalProperty)(message, 'text')) {
1113
+ hydratedTemplate.hydratedContentText = message.text;
1114
+ }
1115
+ else {
1116
+ if ((0, exports.hasOptionalProperty)(message, 'caption')) {
1117
+ hydratedTemplate.hydratedTitleText = message.title;
1118
+ hydratedTemplate.hydratedContentText = message.caption;
1119
+ }
1120
+ ;
1121
+ Object.assign(hydratedTemplate, m);
1122
+ }
1123
+ if ((0, exports.hasOptionalProperty)(message, 'footer')) {
1124
+ hydratedTemplate.hydratedFooterText = message.footer;
1125
+ }
1126
+ hydratedTemplate.templateId = message.id || 'template-' + Date.now(); // deffa-baileys
1127
+ m = {
1128
+ templateMessage: {
1129
+ hydratedFourRowTemplate: hydratedTemplate,
1130
+ hydratedTemplate: hydratedTemplate
1131
+ }
1132
+ };
1133
+ }
1134
+ else if ((0, exports.hasNonNullishProperty)(message, 'nativeFlow')) {
1135
+ const interactiveMessage = {
1136
+ nativeFlowMessage: prepareNativeFlowButtons(message)
1137
+ };
1138
+ if ((0, exports.hasOptionalProperty)(message, 'bizJid')) {
1139
+ interactiveMessage.collectionMessage = {
1140
+ bizJid: message.bizJid,
1141
+ id: message.id,
1142
+ messageVersion: 1
1143
+ };
1144
+ }
1145
+ else if ((0, exports.hasOptionalProperty)(message, 'shopSurface')) {
1146
+ interactiveMessage.shopStorefrontMessage = {
1147
+ surface: message.shopSurface,
1148
+ id: message.id,
1149
+ messageVersion: 1
1150
+ };
1151
+ }
1152
+ if ((0, exports.hasOptionalProperty)(message, 'text')) {
1153
+ interactiveMessage.body = { text: message.text };
1154
+ }
1155
+ else {
1156
+ if ((0, exports.hasOptionalProperty)(message, 'caption')) {
1157
+ const isValidHeader = (0, exports.hasValidInteractiveHeader)(m);
1158
+ if (!isValidHeader) {
1159
+ throw new boom_1.Boom('Invalid media type for interactive message header', { statusCode: 400 });
1160
+ }
1161
+ interactiveMessage.header = {
1162
+ title: message.title || '',
1163
+ subtitle: message.subtitle || '',
1164
+ hasMediaAttachment: isValidHeader
1165
+ };
1166
+ interactiveMessage.body = { text: message.caption };
1167
+ }
1168
+ if ((0, exports.hasOptionalProperty)(message, 'thumbnail') && !!message.thumbnail) {
1169
+ interactiveMessage.jpegThumbnail = message.thumbnail;
1170
+ }
1171
+ interactiveMessage.header = Object.assign(interactiveMessage.header || {}, m);
1172
+ }
1173
+ if ((0, exports.hasOptionalProperty)(message, 'audioFooter')) {
1174
+ const { audioMessage } = await (0, exports.prepareWAMessageMedia)({
1175
+ audio: message.audioFooter
1176
+ }, options);
1177
+ interactiveMessage.footer = {
1178
+ audioMessage,
1179
+ hasMediaAttachment: true
1180
+ };
1181
+ }
1182
+ else if ((0, exports.hasOptionalProperty)(message, 'footer')) {
1183
+ interactiveMessage.footer = { text: message.footer };
1184
+ }
1185
+ m = { interactiveMessage };
1186
+ }
1187
+ else if ((0, exports.hasNonNullishProperty)(message, 'cards')) {
1188
+ const interactiveMessage = {
1189
+ carouselMessage: {
1190
+ cards: await Promise.all(message.cards.map(async (card) => {
1191
+ let carouselHeader = {};
1192
+ if ((0, exports.hasNonNullishProperty)(card, 'product')) {
1193
+ carouselHeader.productMessage = await prepareProductMessage(card, options);
1194
+ }
1195
+ else {
1196
+ carouselHeader = await (0, exports.prepareWAMessageMedia)(card, options).catch(() => ({}));
1197
+ }
1198
+ const isValidHeader = (0, exports.hasValidCarouselHeader)(carouselHeader);
1199
+ if (!isValidHeader) {
1200
+ throw new boom_1.Boom('Invalid media type for carousel card', { statusCode: 400 });
1201
+ }
1202
+ const carouselCard = {
1203
+ nativeFlowMessage: prepareNativeFlowButtons(card.nativeFlow ? card : [])
1204
+ };
1205
+ if ((0, exports.hasOptionalProperty)(card, 'text')) {
1206
+ carouselCard.body = { text: card.text };
1207
+ }
1208
+ else {
1209
+ if ((0, exports.hasOptionalProperty)(card, 'caption')) {
1210
+ carouselCard.header = {
1211
+ title: card.title || '',
1212
+ subtitle: card.subtitle || '',
1213
+ hasMediaAttachment: isValidHeader
1214
+ };
1215
+ carouselCard.body = { text: card.caption };
1216
+ }
1217
+ if ((0, exports.hasOptionalProperty)(card, 'thumbnail') && !!card.thumbnail) {
1218
+ carouselCard.jpegThumbnail = card.thumbnail;
1219
+ }
1220
+ carouselCard.header = Object.assign(carouselCard.header || {}, carouselHeader);
1221
+ }
1222
+ if ((0, exports.hasOptionalProperty)(card, 'audioFooter')) {
1223
+ const { audioMessage } = await (0, exports.prepareWAMessageMedia)({
1224
+ audio: card.audioFooter
1225
+ }, options);
1226
+ carouselCard.footer = {
1227
+ audioMessage,
1228
+ hasMediaAttachment: true
1229
+ };
1230
+ }
1231
+ else if ((0, exports.hasOptionalProperty)(card, 'footer')) {
1232
+ carouselCard.footer = { text: card.footer };
1233
+ }
1234
+ return carouselCard;
1235
+ })),
1236
+ carouselCardType: index_js_3.CarouselCardType.UNKNOWN,
1237
+ messageVersion: 1
1238
+ }
1239
+ };
1240
+ if ((0, exports.hasOptionalProperty)(message, 'text')) {
1241
+ interactiveMessage.body = { text: message.text };
1242
+ }
1243
+ if ((0, exports.hasOptionalProperty)(message, 'footer')) {
1244
+ interactiveMessage.footer = { text: message.footer };
1245
+ }
1246
+ m = { interactiveMessage };
1247
+ }
1248
+ // Lia@Changes 01-02-26 --- Add request payment message
1249
+ else if ((0, exports.hasNonNullishProperty)(message, 'requestPaymentFrom')) {
1250
+ const requestPaymentMessage = {
1251
+ amount: {
1252
+ currencyCode: 'IDR',
1253
+ offset: 1000,
1254
+ value: 1000
1255
+ },
1256
+ amount1000: 1000,
1257
+ currencyCodeIso4217: 'IDR',
1258
+ expiryTimestamp: Date.now(),
1259
+ noteMessage: m,
1260
+ requestFrom: message.requestPaymentFrom,
1261
+ ...message
1262
+ };
1263
+ delete requestPaymentMessage.requestPaymentFrom;
1264
+ if ((0, exports.hasNonNullishProperty)(m, 'extendedTextMessage') || (0, exports.hasNonNullishProperty)(m, 'stickerMessage')) {
1265
+ Object.assign(requestPaymentMessage.noteMessage, m);
1266
+ }
1267
+ else {
1268
+ throw new boom_1.Boom('Invalid message type for request payment note message', { statusCode: 400 });
1269
+ }
1270
+ m = { requestPaymentMessage };
1271
+ }
1272
+ // Lia@Changes 01-02-26 --- Add invoice message
1273
+ else if ((0, exports.hasNonNullishProperty)(message, 'invoiceNote')) {
1274
+ const attachment = m.imageMessage || m.documentMessage;
1275
+ const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
1276
+ const invoiceMessage = {
1277
+ attachmentType: index_js_1.proto.Message.InvoiceMessage.AttachmentType[type === 'DOCUMENT' ? 'PDF' : 'IMAGE'],
1278
+ note: message.invoiceNote
1279
+ };
1280
+ if (attachment) {
1281
+ const { directPath, fileEncSha256, fileSha256, jpegThumbnail = undefined, mediaKey, mediaKeyTimestamp, mimetype } = attachment;
1282
+ Object.assign(invoiceMessage, {
1283
+ attachmentDirectPath: directPath,
1284
+ attachmentFileEncSha256: fileEncSha256,
1285
+ attachmentFileSha256: fileSha256,
1286
+ attachmentJpegThumbnail: jpegThumbnail,
1287
+ attachmentMediaKey: mediaKey,
1288
+ attachmentMediaKeyTimestamp: mediaKeyTimestamp,
1289
+ attachmentMimetype: mimetype,
1290
+ token: (0, generics_js_1.generateMessageIDV2)()
1291
+ });
1292
+ }
1293
+ else {
1294
+ throw new boom_1.Boom('Invalid media type for invoice message', { statusCode: 400 });
1295
+ }
1296
+ m = { invoiceMessage };
1297
+ }
1298
+ // Lia@Changes 31-01-26 --- Add direct externalAdReply access (no need to create contextInfo first)
1299
+ if ((0, exports.hasOptionalProperty)(message, 'externalAdReply') && !!message.externalAdReply) {
1300
+ const messageType = Object.keys(m)[0];
1301
+ const key = m[messageType];
1302
+ const content = message.externalAdReply;
1303
+ if ('thumbnail' in content && !Buffer.isBuffer(content.thumbnail)) {
1304
+ throw new boom_1.Boom('Thumbnail must in buffer type', { statusCode: 400 });
1305
+ }
1306
+ // deffa-baileys fix: jangan paksa fallback ke DONATE_URL kalau user tidak isi url,
1307
+ // karena itu bikin mediaUrl/thumbnailUrl nunjuk ke link yang tidak relevan dan
1308
+ // bisa membuat WA app menolak render preview (mismatch domain vs sourceUrl).
1309
+ const hasUrl = !!content.url && typeof content.url === 'string';
1310
+ const externalAdReply = {
1311
+ ...content,
1312
+ body: content.body,
1313
+ mediaType: content.mediaType || 1,
1314
+ mediaUrl: hasUrl ? content.url : undefined,
1315
+ renderLargerThumbnail: content.largeThumbnail,
1316
+ sourceUrl: hasUrl ? content.url : undefined,
1317
+ thumbnail: content.thumbnail,
1318
+ thumbnailUrl: hasUrl ? content.url + '?update=' + Date.now() : undefined,
1319
+ title: content.title || index_js_2.LIBRARY_NAME,
1320
+ // deffa-baileys fix: showAdAttribution wajib true agar WA app modern konsisten
1321
+ // merender card externalAdReply (tanpa ini WA kadang treat sebagai context info biasa
1322
+ // dan card-nya tidak muncul, terutama di extendedTextMessage).
1323
+ showAdAttribution: content.showAdAttribution ?? true
1324
+ };
1325
+ delete externalAdReply.subTitle;
1326
+ delete externalAdReply.largeThumbnail;
1327
+ delete externalAdReply.url;
1328
+ if (key.contextInfo) {
1329
+ key.contextInfo.externalAdReply = { ...key.contextInfo.externalAdReply, ...externalAdReply };
1330
+ }
1331
+ else if (key) {
1332
+ key.contextInfo = { externalAdReply };
1333
+ }
1334
+ }
1335
+ if (((0, exports.hasOptionalProperty)(message, 'mentions') && message.mentions?.length) ||
1336
+ ((0, exports.hasOptionalProperty)(message, 'mentionAll') && message.mentionAll)) {
1337
+ const messageType = Object.keys(m)[0];
1338
+ const key = m[messageType];
1339
+ if (key && 'contextInfo' in key) {
1340
+ key.contextInfo = key.contextInfo || {};
1341
+ if (message.mentions?.length) {
1342
+ key.contextInfo.mentionedJid = message.mentions;
1343
+ }
1344
+ if (message.mentionAll) {
1345
+ key.contextInfo.nonJidMentions = 1;
1346
+ }
1347
+ }
1348
+ else if (key) {
1349
+ key.contextInfo = {
1350
+ mentionedJid: message.mentions,
1351
+ nonJidMentions: message.mentionAll ? 1 : 0
1352
+ };
1353
+ }
1354
+ }
1355
+ if ((0, exports.hasOptionalProperty)(message, 'contextInfo') && !!message.contextInfo) {
1356
+ const messageType = Object.keys(m)[0];
1357
+ const key = m[messageType];
1358
+ if ('contextInfo' in key && !!key.contextInfo) {
1359
+ key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
1360
+ }
1361
+ else if (key) {
1362
+ key.contextInfo = message.contextInfo;
1363
+ }
1364
+ }
1365
+ // Lia@Changes 31-01-26 --- Add "groupStatus" boolean to set contextInfo.isGroupStatus and wrap message into groupStatusMessageV2
1366
+ if ((0, exports.hasOptionalProperty)(message, 'groupStatus') && !!message.groupStatus) {
1367
+ const messageType = Object.keys(m)[0];
1368
+ const key = m[messageType];
1369
+ if ('contextInfo' in key && !!key.contextInfo) {
1370
+ key.contextInfo.isGroupStatus = message.groupStatus;
1371
+ }
1372
+ else if (key) {
1373
+ key.contextInfo = {
1374
+ isGroupStatus: message.groupStatus
1375
+ };
1376
+ }
1377
+ m = { groupStatusMessageV2: { message: m } };
1378
+ delete message.groupStatus;
1379
+ }
1380
+ // Lia@Changes 06-05-26 --- Add "spoiler" boolean to set contextInfo.isSpoiler and wrap message into spoilerMessage
1381
+ if ((0, exports.hasOptionalProperty)(message, 'spoiler') && !!message.spoiler) {
1382
+ const messageType = Object.keys(m)[0];
1383
+ const key = m[messageType];
1384
+ if ('contextInfo' in key && !!key.contextInfo) {
1385
+ key.contextInfo.isSpoiler = message.spoiler;
1386
+ }
1387
+ else if (key) {
1388
+ key.contextInfo = {
1389
+ isSpoiler: message.spoiler
1390
+ };
1391
+ }
1392
+ m = { spoilerMessage: { message: m } };
1393
+ delete message.spoiler;
1394
+ }
1395
+ // Lia@Changes 02-02-26 --- Add "interactiveAsTemplate" boolean to wrap interactiveMessage into templateMessage
1396
+ else if ((0, exports.hasOptionalProperty)(message, 'interactiveAsTemplate') && !!message.interactiveAsTemplate) {
1397
+ if (!m.interactiveMessage) {
1398
+ throw new boom_1.Boom('Invalid message type for template', { statusCode: 400 }); // deffa-baileys
1399
+ }
1400
+ m = {
1401
+ templateMessage: {
1402
+ interactiveMessageTemplate: m.interactiveMessage,
1403
+ templateId: message.id || 'template-' + Date.now() // deffa-baileys
1404
+ }
1405
+ };
1406
+ delete message.interactiveAsTemplate;
1407
+ }
1408
+ // Lia@Changes 30-01-26 --- Add "ephemeral" boolean to wrap message into ephemeralMessage like "viewOnce"
1409
+ if ((0, exports.hasOptionalProperty)(message, 'ephemeral') && !!message.ephemeral) {
1410
+ m = { ephemeralMessage: { message: m } };
1411
+ delete message.ephemeral;
1412
+ }
1413
+ // Lia@Changes 16-05-26 --- Add wrap message into lottieStickerMessage by isLottie boolean
1414
+ if ((0, exports.hasOptionalProperty)(message, 'isLottie') && !!message.isLottie) {
1415
+ m = { lottieStickerMessage: { message: m } };
1416
+ }
1417
+ else if ((0, exports.hasOptionalProperty)(message, 'viewOnce') && !!message.viewOnce) {
1418
+ m = { viewOnceMessage: { message: m } };
1419
+ }
1420
+ // Lia@Changes 03-02-26 --- Add "viewOnceV2" boolean to wrap message into viewOnceMessageV2 like "viewOnce"
1421
+ else if ((0, exports.hasOptionalProperty)(message, 'viewOnceV2') && !!message.viewOnceV2) {
1422
+ m = { viewOnceMessageV2: { message: m } };
1423
+ delete message.viewOnceV2;
1424
+ }
1425
+ // Lia@Changes 03-02-26 --- Add "viewOnceV2Extension" boolean to wrap message into viewOnceMessageV2Extension like "viewOnce"
1426
+ else if ((0, exports.hasOptionalProperty)(message, 'viewOnceV2Extension') && !!message.viewOnceV2Extension) {
1427
+ m = { viewOnceMessageV2Extension: { message: m } };
1428
+ delete message.viewOnceV2Extension;
1429
+ }
1430
+ if ((0, exports.hasOptionalProperty)(message, 'edit')) {
1431
+ m = {
1432
+ protocolMessage: {
1433
+ key: message.edit,
1434
+ editedMessage: m,
1435
+ timestampMs: Date.now(),
1436
+ type: index_js_3.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
1437
+ }
1438
+ };
1439
+ }
1440
+ if ((0, reporting_utils_js_1.shouldIncludeReportingToken)(m)) {
1441
+ m.messageContextInfo = m.messageContextInfo || {};
1442
+ if (!m.messageContextInfo.messageSecret) {
1443
+ m.messageContextInfo.messageSecret = (0, crypto_1.randomBytes)(32);
1444
+ }
1445
+ }
1446
+ return index_js_3.WAProto.Message.create(m);
1447
+ };
1448
+ exports.generateWAMessageContent = generateWAMessageContent;
1449
+ const generateWAMessageFromContent = (jid, message, options) => {
1450
+ // set timestamp to now
1451
+ // if not specified
1452
+ if (!options.timestamp) {
1453
+ options.timestamp = new Date();
1454
+ }
1455
+ const innerMessage = (0, exports.normalizeMessageContent)(message);
1456
+ const messageContextInfo = message.messageContextInfo;
1457
+ const key = (0, exports.getContentType)(innerMessage);
1458
+ const timestamp = (0, generics_js_1.unixTimestampSeconds)(options.timestamp);
1459
+ const isNewsletter = (0, index_js_4.isJidNewsletter)(jid);
1460
+ const { quoted, userJid } = options;
1461
+ if (quoted) {
1462
+ const participant = quoted.key.fromMe
1463
+ ? userJid // TODO: Add support for LIDs
1464
+ : quoted.participant || quoted.key.participant || quoted.key.remoteJid;
1465
+ let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
1466
+ const msgType = (0, exports.getContentType)(quotedMsg);
1467
+ // strip any redundant properties
1468
+ quotedMsg = index_js_1.proto.Message.create({ [msgType]: quotedMsg[msgType] });
1469
+ const quotedContent = quotedMsg[msgType];
1470
+ if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
1471
+ delete quotedContent.contextInfo;
1472
+ }
1473
+ const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
1474
+ contextInfo.participant = (0, index_js_4.jidNormalizedUser)(participant);
1475
+ contextInfo.stanzaId = quoted.key.id;
1476
+ contextInfo.quotedMessage = quotedMsg;
1477
+ // if a participant is quoted, then it must be a group
1478
+ // hence, remoteJid of group must also be entered
1479
+ if (!isNewsletter && jid !== quoted.key.remoteJid) {
1480
+ contextInfo.remoteJid = quoted.key.remoteJid;
1481
+ }
1482
+ if (contextInfo && innerMessage[key]) {
1483
+ /* @ts-ignore */
1484
+ innerMessage[key].contextInfo = contextInfo;
1485
+ }
1486
+ }
1487
+ if (
1488
+ // if we want to send a disappearing message
1489
+ !!options?.ephemeralExpiration &&
1490
+ // and it's not a protocol message -- delete, toggle disappear message
1491
+ key !== 'protocolMessage' &&
1492
+ // already not converted to disappearing message
1493
+ key !== 'ephemeralMessage' &&
1494
+ // newsletters don't support ephemeral messages
1495
+ !isNewsletter) {
1496
+ /* @ts-ignore */
1497
+ innerMessage[key].contextInfo = {
1498
+ ...(innerMessage[key].contextInfo || {}),
1499
+ expiration: options.ephemeralExpiration || index_js_2.WA_DEFAULT_EPHEMERAL
1500
+ //ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
1501
+ };
1502
+ }
1503
+ // Lia@Changes 30-01-26 --- Add deviceListMetadata inside messageContextInfo for private chat
1504
+ if (messageContextInfo?.messageSecret && ((0, index_js_4.isPnUser)(jid) || (0, index_js_4.isLidUser)(jid))) {
1505
+ messageContextInfo.deviceListMetadata = {
1506
+ recipientKeyHash: (0, crypto_1.randomBytes)(10),
1507
+ recipientTimestamp: (0, generics_js_1.unixTimestampSeconds)()
1508
+ };
1509
+ messageContextInfo.deviceListMetadataVersion = 2;
1510
+ }
1511
+ message = index_js_3.WAProto.Message.create(message);
1512
+ const messageJSON = {
1513
+ key: {
1514
+ remoteJid: jid,
1515
+ fromMe: true,
1516
+ id: options?.messageId || (0, generics_js_1.generateMessageIDV2)()
1517
+ },
1518
+ message: message,
1519
+ messageTimestamp: timestamp,
1520
+ messageStubParameters: [],
1521
+ participant: (0, index_js_4.isJidGroup)(jid) || (0, index_js_4.isJidStatusBroadcast)(jid) ? userJid : undefined, // TODO: Add support for LIDs
1522
+ status: index_js_3.WAMessageStatus.PENDING
1523
+ };
1524
+ return index_js_3.WAProto.WebMessageInfo.fromObject(messageJSON);
1525
+ };
1526
+ exports.generateWAMessageFromContent = generateWAMessageFromContent;
1527
+ const generateWAMessage = async (jid, content, options) => {
1528
+ // ensure msg ID is with every log
1529
+ options.logger = options?.logger?.child({ msgId: options.messageId });
1530
+ // Pass jid in the options to generateWAMessageContent
1531
+ if (jid) {
1532
+ options.jid = jid;
1533
+ }
1534
+ return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, options), options);
1535
+ };
1536
+ exports.generateWAMessage = generateWAMessage;
1537
+ /** Get the key to access the true type of content */
1538
+ const getContentType = (content) => {
1539
+ if (content) {
1540
+ const keys = Object.keys(content);
1541
+ const key = keys.find(k => (k === 'conversation' || k.includes('Message')) && k !== 'senderKeyDistributionMessage');
1542
+ return key;
1543
+ }
1544
+ };
1545
+ exports.getContentType = getContentType;
1546
+ /**
1547
+ * Normalizes ephemeral, view once messages to regular message content
1548
+ * Eg. image messages in ephemeral messages, in view once messages etc.
1549
+ * @param content
1550
+ * @returns
1551
+ */
1552
+ const normalizeMessageContent = (content) => {
1553
+ if (!content) {
1554
+ return undefined;
1555
+ }
1556
+ // set max iterations to prevent an infinite loop
1557
+ for (let i = 0; i < 5; i++) {
1558
+ const inner = getFutureProofMessage(content);
1559
+ if (!inner) {
1560
+ break;
1561
+ }
1562
+ content = inner.message;
1563
+ }
1564
+ return content;
1565
+ // Lia@Changes 03-02-26 --- Add all futureProofMessage into getFutureProofMessage()
1566
+ function getFutureProofMessage(message) {
1567
+ return (message?.associatedChildMessage ||
1568
+ message?.botForwardedMessage ||
1569
+ message?.botInvokeMessage ||
1570
+ message?.botTaskMessage ||
1571
+ message?.documentWithCaptionMessage ||
1572
+ message?.editedMessage ||
1573
+ message?.ephemeralMessage ||
1574
+ message?.eventCoverImage ||
1575
+ message?.groupMentionedMessage ||
1576
+ message?.groupStatusMentionMessage ||
1577
+ message?.groupStatusMessage ||
1578
+ message?.groupStatusMessageV2 ||
1579
+ message?.limitSharingMessage ||
1580
+ message?.lottieStickerMessage ||
1581
+ message?.newsletterAdminProfileMessage ||
1582
+ message?.newsletterAdminProfileMessageV2 ||
1583
+ message?.newsletterAdminProfileStatusMessage ||
1584
+ message?.pollCreationMessageV4 ||
1585
+ message?.pollCreationOptionImageMessage ||
1586
+ message?.questionMessage ||
1587
+ message?.questionReplyMessage ||
1588
+ message?.spoilerMessage ||
1589
+ message?.statusAddYours ||
1590
+ message?.statusMentionMessage ||
1591
+ message?.viewOnceMessage ||
1592
+ message?.viewOnceMessageV2 ||
1593
+ message?.viewOnceMessageV2Extension);
1594
+ }
1595
+ };
1596
+ exports.normalizeMessageContent = normalizeMessageContent;
1597
+ /**
1598
+ * Extract the true message content from a message
1599
+ * Eg. extracts the inner message from a disappearing message/view once message
1600
+ */
1601
+ const extractMessageContent = (content) => {
1602
+ const extractFromTemplateMessage = (msg) => {
1603
+ if (msg.imageMessage) {
1604
+ return { imageMessage: msg.imageMessage };
1605
+ }
1606
+ else if (msg.documentMessage) {
1607
+ return { documentMessage: msg.documentMessage };
1608
+ }
1609
+ else if (msg.videoMessage) {
1610
+ return { videoMessage: msg.videoMessage };
1611
+ }
1612
+ else if (msg.locationMessage) {
1613
+ return { locationMessage: msg.locationMessage };
1614
+ }
1615
+ else {
1616
+ return {
1617
+ conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
1618
+ };
1619
+ }
1620
+ };
1621
+ content = (0, exports.normalizeMessageContent)(content);
1622
+ if (content?.buttonsMessage) {
1623
+ return extractFromTemplateMessage(content.buttonsMessage);
1624
+ }
1625
+ if (content?.templateMessage?.hydratedFourRowTemplate) {
1626
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
1627
+ }
1628
+ if (content?.templateMessage?.hydratedTemplate) {
1629
+ return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
1630
+ }
1631
+ if (content?.templateMessage?.fourRowTemplate) {
1632
+ return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
1633
+ }
1634
+ return content;
1635
+ };
1636
+ exports.extractMessageContent = extractMessageContent;
1637
+ /**
1638
+ * Returns the device predicted by message ID
1639
+ */
1640
+ const getDevice = (id) => /^3A.{18}$/.test(id)
1641
+ ? 'ios'
1642
+ : /^3E.{20}$/.test(id)
1643
+ ? 'web'
1644
+ : /^(.{21}|.{32})$/.test(id)
1645
+ ? 'android'
1646
+ : /^(3F|.{18}$)/.test(id)
1647
+ ? 'desktop'
1648
+ : 'unknown';
1649
+ exports.getDevice = getDevice;
1650
+ /** Upserts a receipt in the message */
1651
+ const updateMessageWithReceipt = (msg, receipt) => {
1652
+ msg.userReceipt = msg.userReceipt || [];
1653
+ const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
1654
+ if (recp) {
1655
+ Object.assign(recp, receipt);
1656
+ }
1657
+ else {
1658
+ msg.userReceipt.push(receipt);
1659
+ }
1660
+ };
1661
+ exports.updateMessageWithReceipt = updateMessageWithReceipt;
1662
+ /** Update the message with a new reaction */
1663
+ const updateMessageWithReaction = (msg, reaction) => {
1664
+ const authorID = (0, generics_js_1.getKeyAuthor)(reaction.key);
1665
+ const reactions = (msg.reactions || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.key) !== authorID);
1666
+ reaction.text = reaction.text || '';
1667
+ reactions.push(reaction);
1668
+ msg.reactions = reactions;
1669
+ };
1670
+ exports.updateMessageWithReaction = updateMessageWithReaction;
1671
+ /** Update the message with a new poll update */
1672
+ const updateMessageWithPollUpdate = (msg, update) => {
1673
+ const authorID = (0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey);
1674
+ const reactions = (msg.pollUpdates || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
1675
+ if (update.vote?.selectedOptions?.length) {
1676
+ reactions.push(update);
1677
+ }
1678
+ msg.pollUpdates = reactions;
1679
+ };
1680
+ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
1681
+ /** Update the message with a new event response */
1682
+ const updateMessageWithEventResponse = (msg, update) => {
1683
+ const authorID = (0, generics_js_1.getKeyAuthor)(update.eventResponseMessageKey);
1684
+ const responses = (msg.eventResponses || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.eventResponseMessageKey) !== authorID);
1685
+ responses.push(update);
1686
+ msg.eventResponses = responses;
1687
+ };
1688
+ exports.updateMessageWithEventResponse = updateMessageWithEventResponse;
1689
+ /**
1690
+ * Aggregates all poll updates in a poll.
1691
+ * @param msg the poll creation message
1692
+ * @param meId your jid
1693
+ * @returns A list of options & their voters
1694
+ */
1695
+ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
1696
+ const opts = message?.pollCreationMessage?.options ||
1697
+ message?.pollCreationMessageV2?.options ||
1698
+ message?.pollCreationMessageV3?.options ||
1699
+ [];
1700
+ const voteHashMap = opts.reduce((acc, opt) => {
1701
+ const hash = (0, crypto_js_1.sha256)(Buffer.from(opt.optionName || '')).toString();
1702
+ acc[hash] = {
1703
+ name: opt.optionName || '',
1704
+ voters: []
1705
+ };
1706
+ return acc;
1707
+ }, {});
1708
+ for (const update of pollUpdates || []) {
1709
+ const { vote } = update;
1710
+ if (!vote) {
1711
+ continue;
1712
+ }
1713
+ for (const option of vote.selectedOptions || []) {
1714
+ const hash = option.toString();
1715
+ let data = voteHashMap[hash];
1716
+ if (!data) {
1717
+ voteHashMap[hash] = {
1718
+ name: 'Unknown',
1719
+ voters: []
1720
+ };
1721
+ data = voteHashMap[hash];
1722
+ }
1723
+ voteHashMap[hash].voters.push((0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
1724
+ }
1725
+ }
1726
+ return Object.values(voteHashMap);
1727
+ }
1728
+ /**
1729
+ * Aggregates all event responses in an event message.
1730
+ * @param msg the event creation message
1731
+ * @param meId your jid
1732
+ * @returns A list of response types & their responders
1733
+ */
1734
+ function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
1735
+ const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
1736
+ const responseMap = {};
1737
+ for (const type of responseTypes) {
1738
+ responseMap[type] = {
1739
+ response: type,
1740
+ responders: []
1741
+ };
1742
+ }
1743
+ for (const update of eventResponses || []) {
1744
+ const responseType = update.eventResponse || 'UNKNOWN';
1745
+ if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
1746
+ responseMap[responseType].responders.push((0, generics_js_1.getKeyAuthor)(update.eventResponseMessageKey, meId));
1747
+ }
1748
+ }
1749
+ return Object.values(responseMap);
1750
+ }
1751
+ /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
1752
+ const aggregateMessageKeysNotFromMe = (keys) => {
1753
+ const keyMap = {};
1754
+ for (const { remoteJid, id, participant, fromMe } of keys) {
1755
+ if (!fromMe) {
1756
+ const uqKey = `${remoteJid}:${participant || ''}`;
1757
+ if (!keyMap[uqKey]) {
1758
+ keyMap[uqKey] = {
1759
+ jid: remoteJid,
1760
+ participant: participant,
1761
+ messageIds: []
1762
+ };
1763
+ }
1764
+ keyMap[uqKey].messageIds.push(id);
1765
+ }
1766
+ }
1767
+ return Object.values(keyMap);
1768
+ };
1769
+ exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
1770
+ const REUPLOAD_REQUIRED_STATUS = [410, 404];
1771
+ /**
1772
+ * Downloads the given message. Throws an error if it's not a media message
1773
+ */
1774
+ const downloadMediaMessage = async (message, type, options, ctx) => {
1775
+ const result = await downloadMsg().catch(async (error) => {
1776
+ if (ctx &&
1777
+ typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
1778
+ REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
1779
+ ctx.logger.info({ key: message.key }, 'sending reupload media request...');
1780
+ // request reupload
1781
+ message = await ctx.reuploadRequest(message);
1782
+ const result = await downloadMsg();
1783
+ return result;
1784
+ }
1785
+ throw error;
1786
+ });
1787
+ return result;
1788
+ async function downloadMsg() {
1789
+ const mContent = (0, exports.extractMessageContent)(message.message);
1790
+ if (!mContent) {
1791
+ throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
1792
+ }
1793
+ const contentType = (0, exports.getContentType)(mContent);
1794
+ let mediaType = contentType?.replace('Message', '');
1795
+ const media = mContent[contentType];
1796
+ if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
1797
+ throw new boom_1.Boom(`"${contentType}" message is not a media message`);
1798
+ }
1799
+ let download;
1800
+ if ('thumbnailDirectPath' in media && !('url' in media)) {
1801
+ download = {
1802
+ directPath: media.thumbnailDirectPath,
1803
+ mediaKey: media.mediaKey
1804
+ };
1805
+ mediaType = 'thumbnail-link';
1806
+ }
1807
+ else {
1808
+ download = media;
1809
+ }
1810
+ const stream = await (0, messages_media_js_1.downloadContentFromMessage)(download, mediaType, options);
1811
+ if (type === 'buffer') {
1812
+ const bufferArray = [];
1813
+ for await (const chunk of stream) {
1814
+ bufferArray.push(chunk);
1815
+ }
1816
+ return Buffer.concat(bufferArray);
1817
+ }
1818
+ return stream;
1819
+ }
1820
+ };
1821
+ exports.downloadMediaMessage = downloadMediaMessage;
1822
+ /** Checks whether the given message is a media message; if it is returns the inner content */
1823
+ const assertMediaContent = (content) => {
1824
+ content = (0, exports.extractMessageContent)(content);
1825
+ const mediaContent = content?.documentMessage ||
1826
+ content?.imageMessage ||
1827
+ content?.videoMessage ||
1828
+ content?.audioMessage ||
1829
+ content?.stickerMessage;
1830
+ if (!mediaContent) {
1831
+ throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
1832
+ }
1833
+ return mediaContent;
1834
+ };
1835
+ exports.assertMediaContent = assertMediaContent;
1836
+ /**
1837
+ * Checks if a WebP buffer is animated by looking for VP8X chunk with animation flag
1838
+ * or ANIM/ANMF chunks
1839
+ */
1840
+ const isAnimatedWebP = (buffer) => {
1841
+ // WebP must start with RIFF....WEBP
1842
+ if (buffer.length < 12 ||
1843
+ buffer[0] !== 0x52 ||
1844
+ buffer[1] !== 0x49 ||
1845
+ buffer[2] !== 0x46 ||
1846
+ buffer[3] !== 0x46 ||
1847
+ buffer[8] !== 0x57 ||
1848
+ buffer[9] !== 0x45 ||
1849
+ buffer[10] !== 0x42 ||
1850
+ buffer[11] !== 0x50) {
1851
+ return false;
1852
+ }
1853
+ ;
1854
+ // Parse chunks starting after RIFF header (12 bytes)
1855
+ let offset = 12;
1856
+ while (offset < buffer.length - 8) {
1857
+ const chunkFourCC = buffer.toString('ascii', offset, offset + 4);
1858
+ const chunkSize = buffer.readUInt32LE(offset + 4);
1859
+ if (chunkFourCC === 'VP8X') {
1860
+ // VP8X extended header, check animation flag (bit 1 at offset+8)
1861
+ const flagsOffset = offset + 8;
1862
+ if (flagsOffset < buffer.length) {
1863
+ const flags = buffer[flagsOffset];
1864
+ if (flags & 0x02) {
1865
+ return true;
1866
+ }
1867
+ ;
1868
+ }
1869
+ ;
1870
+ }
1871
+ else if (chunkFourCC === 'ANIM' || chunkFourCC === 'ANMF') {
1872
+ // ANIM or ANMF chunks indicate animation
1873
+ return true;
1874
+ }
1875
+ ;
1876
+ // Move to next chunk (chunk size + 8 bytes header, padded to even)
1877
+ offset += 8 + chunkSize + (chunkSize % 2);
1878
+ }
1879
+ ;
1880
+ return false;
1881
+ };
1882
+ /**
1883
+ * Checks if a buffer is a WebP file
1884
+ */
1885
+ const isWebPBuffer = (buffer) => {
1886
+ return (buffer.length >= 12 &&
1887
+ buffer[0] === 0x52 &&
1888
+ buffer[1] === 0x49 &&
1889
+ buffer[2] === 0x46 &&
1890
+ buffer[3] === 0x46 &&
1891
+ buffer[8] === 0x57 &&
1892
+ buffer[9] === 0x45 &&
1893
+ buffer[10] === 0x42 &&
1894
+ buffer[11] === 0x50);
1895
+ };
1896
+ /**
1897
+ * Lia@Changes 30-01-26
1898
+ * ---
1899
+ * Determines whether a message should include a Biz Binary Node.
1900
+ * A Biz Binary Node is added only for interactive messages
1901
+ * such as buttons or other supported interactive types.
1902
+ */
1903
+ const shouldIncludeBizBinaryNode = (message) => !!(message.buttonsMessage ||
1904
+ message.listMessage ||
1905
+ message.templateMessage ||
1906
+ (message.interactiveMessage &&
1907
+ message.interactiveMessage.nativeFlowMessage));
1908
+ exports.shouldIncludeBizBinaryNode = shouldIncludeBizBinaryNode;
1909
+ //# sourceMappingURL=messages.js.map