@ubedsockets/baileys 1.6.4 → 1.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (394) hide show
  1. package/engine-requirements.js +10 -0
  2. package/lib/Defaults/index.d.ts +75 -0
  3. package/lib/Defaults/index.d.ts.map +1 -0
  4. package/lib/Defaults/index.js +76 -92
  5. package/lib/Defaults/index.js.map +1 -0
  6. package/lib/Signal/Group/ciphertext-message.d.ts +10 -0
  7. package/lib/Signal/Group/ciphertext-message.d.ts.map +1 -0
  8. package/lib/Signal/Group/ciphertext-message.js +2 -5
  9. package/lib/Signal/Group/ciphertext-message.js.map +1 -0
  10. package/lib/Signal/Group/group-session-builder.d.ts +15 -0
  11. package/lib/Signal/Group/group-session-builder.d.ts.map +1 -0
  12. package/lib/Signal/Group/group-session-builder.js +7 -41
  13. package/lib/Signal/Group/group-session-builder.js.map +1 -0
  14. package/lib/Signal/Group/group_cipher.d.ts +17 -0
  15. package/lib/Signal/Group/group_cipher.d.ts.map +1 -0
  16. package/lib/Signal/Group/group_cipher.js +37 -51
  17. package/lib/Signal/Group/group_cipher.js.map +1 -0
  18. package/lib/Signal/Group/index.d.ts +12 -0
  19. package/lib/Signal/Group/index.d.ts.map +1 -0
  20. package/lib/Signal/Group/index.js +12 -57
  21. package/lib/Signal/Group/index.js.map +1 -0
  22. package/lib/Signal/Group/keyhelper.d.ts +11 -0
  23. package/lib/Signal/Group/keyhelper.d.ts.map +1 -0
  24. package/lib/Signal/Group/keyhelper.js +7 -44
  25. package/lib/Signal/Group/keyhelper.js.map +1 -0
  26. package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
  27. package/lib/Signal/Group/sender-chain-key.d.ts.map +1 -0
  28. package/lib/Signal/Group/sender-chain-key.js +7 -15
  29. package/lib/Signal/Group/sender-chain-key.js.map +1 -0
  30. package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
  31. package/lib/Signal/Group/sender-key-distribution-message.d.ts.map +1 -0
  32. package/lib/Signal/Group/sender-key-distribution-message.js +8 -11
  33. package/lib/Signal/Group/sender-key-distribution-message.js.map +1 -0
  34. package/lib/Signal/Group/sender-key-message.d.ts +19 -0
  35. package/lib/Signal/Group/sender-key-message.d.ts.map +1 -0
  36. package/lib/Signal/Group/sender-key-message.js +9 -12
  37. package/lib/Signal/Group/sender-key-message.js.map +1 -0
  38. package/lib/Signal/Group/sender-key-name.d.ts +18 -0
  39. package/lib/Signal/Group/sender-key-name.d.ts.map +1 -0
  40. package/lib/Signal/Group/sender-key-name.js +2 -5
  41. package/lib/Signal/Group/sender-key-name.js.map +1 -0
  42. package/lib/Signal/Group/sender-key-record.d.ts +31 -0
  43. package/lib/Signal/Group/sender-key-record.d.ts.map +1 -0
  44. package/lib/Signal/Group/sender-key-record.js +9 -21
  45. package/lib/Signal/Group/sender-key-record.js.map +1 -0
  46. package/lib/Signal/Group/sender-key-state.d.ts +39 -0
  47. package/lib/Signal/Group/sender-key-state.d.ts.map +1 -0
  48. package/lib/Signal/Group/sender-key-state.js +27 -42
  49. package/lib/Signal/Group/sender-key-state.js.map +1 -0
  50. package/lib/Signal/Group/sender-message-key.d.ts +12 -0
  51. package/lib/Signal/Group/sender-message-key.d.ts.map +1 -0
  52. package/lib/Signal/Group/sender-message-key.js +4 -7
  53. package/lib/Signal/Group/sender-message-key.js.map +1 -0
  54. package/lib/Signal/libsignal.d.ts +5 -0
  55. package/lib/Signal/libsignal.d.ts.map +1 -0
  56. package/lib/Signal/libsignal.js +347 -90
  57. package/lib/Signal/libsignal.js.map +1 -0
  58. package/lib/Signal/lid-mapping.d.ts +23 -0
  59. package/lib/Signal/lid-mapping.d.ts.map +1 -0
  60. package/lib/Signal/lid-mapping.js +277 -0
  61. package/lib/Signal/lid-mapping.js.map +1 -0
  62. package/lib/Socket/Client/index.d.ts +3 -0
  63. package/lib/Socket/Client/index.d.ts.map +1 -0
  64. package/lib/Socket/Client/index.js +3 -18
  65. package/lib/Socket/Client/index.js.map +1 -0
  66. package/lib/Socket/Client/types.d.ts +16 -0
  67. package/lib/Socket/Client/types.d.ts.map +1 -0
  68. package/lib/Socket/Client/types.js +4 -6
  69. package/lib/Socket/Client/types.js.map +1 -0
  70. package/lib/Socket/Client/websocket.d.ts +13 -0
  71. package/lib/Socket/Client/websocket.d.ts.map +1 -0
  72. package/lib/Socket/Client/websocket.js +21 -78
  73. package/lib/Socket/Client/websocket.js.map +1 -0
  74. package/lib/Socket/business.d.ts +217 -0
  75. package/lib/Socket/business.d.ts.map +1 -0
  76. package/lib/Socket/business.js +162 -43
  77. package/lib/Socket/business.js.map +1 -0
  78. package/lib/Socket/chats.d.ts +124 -0
  79. package/lib/Socket/chats.d.ts.map +1 -0
  80. package/lib/Socket/chats.js +571 -249
  81. package/lib/Socket/chats.js.map +1 -0
  82. package/lib/Socket/communities.d.ts +273 -0
  83. package/lib/Socket/communities.d.ts.map +1 -0
  84. package/lib/Socket/communities.js +431 -0
  85. package/lib/Socket/communities.js.map +1 -0
  86. package/lib/Socket/groups.d.ts +161 -0
  87. package/lib/Socket/groups.d.ts.map +1 -0
  88. package/lib/Socket/groups.js +114 -99
  89. package/lib/Socket/groups.js.map +1 -0
  90. package/lib/Socket/index.d.ts +260 -0
  91. package/lib/Socket/index.d.ts.map +1 -0
  92. package/lib/Socket/index.js +11 -9
  93. package/lib/Socket/index.js.map +1 -0
  94. package/lib/Socket/messages-recv.d.ts +203 -0
  95. package/lib/Socket/messages-recv.d.ts.map +1 -0
  96. package/lib/Socket/messages-recv.js +1277 -559
  97. package/lib/Socket/messages-recv.js.map +1 -0
  98. package/lib/Socket/messages-send.d.ts +199 -0
  99. package/lib/Socket/messages-send.d.ts.map +1 -0
  100. package/lib/Socket/messages-send.js +674 -669
  101. package/lib/Socket/messages-send.js.map +1 -0
  102. package/lib/Socket/mex.d.ts +3 -0
  103. package/lib/Socket/mex.d.ts.map +1 -0
  104. package/lib/Socket/mex.js +42 -0
  105. package/lib/Socket/mex.js.map +1 -0
  106. package/lib/Socket/newsletter.d.ts +170 -0
  107. package/lib/Socket/newsletter.d.ts.map +1 -0
  108. package/lib/Socket/newsletter.js +149 -286
  109. package/lib/Socket/newsletter.js.map +1 -0
  110. package/lib/Socket/socket.d.ts +59 -0
  111. package/lib/Socket/socket.d.ts.map +1 -0
  112. package/lib/Socket/socket.js +548 -235
  113. package/lib/Socket/socket.js.map +1 -0
  114. package/lib/Types/Auth.d.ts +117 -0
  115. package/lib/Types/Auth.d.ts.map +1 -0
  116. package/lib/Types/Auth.js +2 -2
  117. package/lib/Types/Auth.js.map +1 -0
  118. package/lib/Types/Bussines.d.ts +25 -0
  119. package/lib/Types/Bussines.d.ts.map +1 -0
  120. package/lib/Types/Bussines.js +2 -0
  121. package/lib/Types/Bussines.js.map +1 -0
  122. package/lib/Types/Call.d.ts +15 -0
  123. package/lib/Types/Call.d.ts.map +1 -0
  124. package/lib/Types/Call.js +2 -2
  125. package/lib/Types/Call.js.map +1 -0
  126. package/lib/Types/Chat.d.ts +124 -0
  127. package/lib/Types/Chat.d.ts.map +1 -0
  128. package/lib/Types/Chat.js +8 -4
  129. package/lib/Types/Chat.js.map +1 -0
  130. package/lib/Types/Contact.d.ts +26 -0
  131. package/lib/Types/Contact.d.ts.map +1 -0
  132. package/lib/Types/Contact.js +2 -2
  133. package/lib/Types/Contact.js.map +1 -0
  134. package/lib/Types/Events.d.ts +256 -0
  135. package/lib/Types/Events.d.ts.map +1 -0
  136. package/lib/Types/Events.js +2 -2
  137. package/lib/Types/Events.js.map +1 -0
  138. package/lib/Types/GroupMetadata.d.ts +71 -0
  139. package/lib/Types/GroupMetadata.d.ts.map +1 -0
  140. package/lib/Types/GroupMetadata.js +2 -2
  141. package/lib/Types/GroupMetadata.js.map +1 -0
  142. package/lib/Types/Label.d.ts +47 -0
  143. package/lib/Types/Label.d.ts.map +1 -0
  144. package/lib/Types/Label.js +3 -5
  145. package/lib/Types/Label.js.map +1 -0
  146. package/lib/Types/LabelAssociation.d.ts +30 -0
  147. package/lib/Types/LabelAssociation.d.ts.map +1 -0
  148. package/lib/Types/LabelAssociation.js +3 -5
  149. package/lib/Types/LabelAssociation.js.map +1 -0
  150. package/lib/Types/Message.d.ts +320 -0
  151. package/lib/Types/Message.d.ts.map +1 -0
  152. package/lib/Types/Message.js +11 -7
  153. package/lib/Types/Message.js.map +1 -0
  154. package/lib/Types/Mex.d.ts +141 -0
  155. package/lib/Types/Mex.d.ts.map +1 -0
  156. package/lib/Types/Mex.js +37 -0
  157. package/lib/Types/Mex.js.map +1 -0
  158. package/lib/Types/Product.d.ts +79 -0
  159. package/lib/Types/Product.d.ts.map +1 -0
  160. package/lib/Types/Product.js +2 -2
  161. package/lib/Types/Product.js.map +1 -0
  162. package/lib/Types/Signal.d.ts +87 -0
  163. package/lib/Types/Signal.d.ts.map +1 -0
  164. package/lib/Types/Signal.js +2 -2
  165. package/lib/Types/Signal.js.map +1 -0
  166. package/lib/Types/Socket.d.ts +136 -0
  167. package/lib/Types/Socket.d.ts.map +1 -0
  168. package/lib/Types/Socket.js +3 -2
  169. package/lib/Types/Socket.js.map +1 -0
  170. package/lib/Types/State.d.ts +97 -0
  171. package/lib/Types/State.d.ts.map +1 -0
  172. package/lib/Types/State.js +56 -2
  173. package/lib/Types/State.js.map +1 -0
  174. package/lib/Types/USync.d.ts +26 -0
  175. package/lib/Types/USync.d.ts.map +1 -0
  176. package/lib/Types/USync.js +2 -2
  177. package/lib/Types/USync.js.map +1 -0
  178. package/lib/Types/index.d.ts +65 -0
  179. package/lib/Types/index.d.ts.map +1 -0
  180. package/lib/Types/index.js +15 -31
  181. package/lib/Types/index.js.map +1 -0
  182. package/lib/Utils/auth-utils.d.ts +24 -0
  183. package/lib/Utils/auth-utils.d.ts.map +1 -0
  184. package/lib/Utils/auth-utils.js +239 -136
  185. package/lib/Utils/auth-utils.js.map +1 -0
  186. package/lib/Utils/browser-utils.d.ts +4 -0
  187. package/lib/Utils/browser-utils.d.ts.map +1 -0
  188. package/lib/Utils/browser-utils.js +28 -0
  189. package/lib/Utils/browser-utils.js.map +1 -0
  190. package/lib/Utils/business.d.ts +23 -0
  191. package/lib/Utils/business.d.ts.map +1 -0
  192. package/lib/Utils/business.js +66 -69
  193. package/lib/Utils/business.js.map +1 -0
  194. package/lib/Utils/chat-utils.d.ts +100 -0
  195. package/lib/Utils/chat-utils.d.ts.map +1 -0
  196. package/lib/Utils/chat-utils.js +380 -238
  197. package/lib/Utils/chat-utils.js.map +1 -0
  198. package/lib/Utils/companion-reg-client-utils.d.ts +17 -0
  199. package/lib/Utils/companion-reg-client-utils.d.ts.map +1 -0
  200. package/lib/Utils/companion-reg-client-utils.js +35 -0
  201. package/lib/Utils/companion-reg-client-utils.js.map +1 -0
  202. package/lib/Utils/crypto.d.ts +37 -0
  203. package/lib/Utils/crypto.d.ts.map +1 -0
  204. package/lib/Utils/crypto.js +56 -127
  205. package/lib/Utils/crypto.js.map +1 -0
  206. package/lib/Utils/decode-wa-message.d.ts +66 -0
  207. package/lib/Utils/decode-wa-message.d.ts.map +1 -0
  208. package/lib/Utils/decode-wa-message.js +173 -63
  209. package/lib/Utils/decode-wa-message.js.map +1 -0
  210. package/lib/Utils/event-buffer.d.ts +36 -0
  211. package/lib/Utils/event-buffer.d.ts.map +1 -0
  212. package/lib/Utils/event-buffer.js +174 -70
  213. package/lib/Utils/event-buffer.js.map +1 -0
  214. package/lib/Utils/generics.d.ts +91 -0
  215. package/lib/Utils/generics.d.ts.map +1 -0
  216. package/lib/Utils/generics.js +159 -207
  217. package/lib/Utils/generics.js.map +1 -0
  218. package/lib/Utils/history.d.ts +24 -0
  219. package/lib/Utils/history.d.ts.map +1 -0
  220. package/lib/Utils/history.js +93 -53
  221. package/lib/Utils/history.js.map +1 -0
  222. package/lib/Utils/identity-change-handler.d.ts +44 -0
  223. package/lib/Utils/identity-change-handler.d.ts.map +1 -0
  224. package/lib/Utils/identity-change-handler.js +50 -0
  225. package/lib/Utils/identity-change-handler.js.map +1 -0
  226. package/lib/Utils/index.d.ts +22 -0
  227. package/lib/Utils/index.d.ts.map +1 -0
  228. package/lib/Utils/index.js +22 -33
  229. package/lib/Utils/index.js.map +1 -0
  230. package/lib/Utils/link-preview.d.ts +21 -0
  231. package/lib/Utils/link-preview.d.ts.map +1 -0
  232. package/lib/Utils/link-preview.js +17 -58
  233. package/lib/Utils/link-preview.js.map +1 -0
  234. package/lib/Utils/logger.d.ts +12 -0
  235. package/lib/Utils/logger.d.ts.map +1 -0
  236. package/lib/Utils/logger.js +3 -7
  237. package/lib/Utils/logger.js.map +1 -0
  238. package/lib/Utils/lt-hash.d.ts +8 -0
  239. package/lib/Utils/lt-hash.d.ts.map +1 -0
  240. package/lib/Utils/lt-hash.js +3 -46
  241. package/lib/Utils/lt-hash.js.map +1 -0
  242. package/lib/Utils/make-mutex.d.ts +9 -0
  243. package/lib/Utils/make-mutex.d.ts.map +1 -0
  244. package/lib/Utils/make-mutex.js +24 -34
  245. package/lib/Utils/make-mutex.js.map +1 -0
  246. package/lib/Utils/message-retry-manager.d.ts +115 -0
  247. package/lib/Utils/message-retry-manager.d.ts.map +1 -0
  248. package/lib/Utils/message-retry-manager.js +265 -0
  249. package/lib/Utils/message-retry-manager.js.map +1 -0
  250. package/lib/Utils/messages-media.d.ts +133 -0
  251. package/lib/Utils/messages-media.d.ts.map +1 -0
  252. package/lib/Utils/messages-media.js +483 -744
  253. package/lib/Utils/messages-media.js.map +1 -0
  254. package/lib/Utils/messages.d.ts +91 -0
  255. package/lib/Utils/messages.d.ts.map +1 -0
  256. package/lib/Utils/messages.js +411 -621
  257. package/lib/Utils/messages.js.map +1 -0
  258. package/lib/Utils/noise-handler.d.ts +20 -0
  259. package/lib/Utils/noise-handler.d.ts.map +1 -0
  260. package/lib/Utils/noise-handler.js +149 -99
  261. package/lib/Utils/noise-handler.js.map +1 -0
  262. package/lib/Utils/offline-node-processor.d.ts +17 -0
  263. package/lib/Utils/offline-node-processor.d.ts.map +1 -0
  264. package/lib/Utils/offline-node-processor.js +40 -0
  265. package/lib/Utils/offline-node-processor.js.map +1 -0
  266. package/lib/Utils/pre-key-manager.d.ts +28 -0
  267. package/lib/Utils/pre-key-manager.d.ts.map +1 -0
  268. package/lib/Utils/pre-key-manager.js +106 -0
  269. package/lib/Utils/pre-key-manager.js.map +1 -0
  270. package/lib/Utils/process-message.d.ts +60 -0
  271. package/lib/Utils/process-message.d.ts.map +1 -0
  272. package/lib/Utils/process-message.js +459 -150
  273. package/lib/Utils/process-message.js.map +1 -0
  274. package/lib/Utils/reporting-utils.d.ts +11 -0
  275. package/lib/Utils/reporting-utils.d.ts.map +1 -0
  276. package/lib/Utils/reporting-utils.js +258 -0
  277. package/lib/Utils/reporting-utils.js.map +1 -0
  278. package/lib/Utils/signal.d.ts +47 -0
  279. package/lib/Utils/signal.d.ts.map +1 -0
  280. package/lib/Utils/signal.js +112 -73
  281. package/lib/Utils/signal.js.map +1 -0
  282. package/lib/Utils/stanza-ack.d.ts +11 -0
  283. package/lib/Utils/stanza-ack.d.ts.map +1 -0
  284. package/lib/Utils/stanza-ack.js +38 -0
  285. package/lib/Utils/stanza-ack.js.map +1 -0
  286. package/lib/Utils/sync-action-utils.d.ts +19 -0
  287. package/lib/Utils/sync-action-utils.d.ts.map +1 -0
  288. package/lib/Utils/sync-action-utils.js +49 -0
  289. package/lib/Utils/sync-action-utils.js.map +1 -0
  290. package/lib/Utils/tc-token-utils.d.ts +37 -0
  291. package/lib/Utils/tc-token-utils.d.ts.map +1 -0
  292. package/lib/Utils/tc-token-utils.js +163 -0
  293. package/lib/Utils/tc-token-utils.js.map +1 -0
  294. package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
  295. package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -0
  296. package/lib/Utils/use-multi-file-auth-state.js +23 -27
  297. package/lib/Utils/use-multi-file-auth-state.js.map +1 -0
  298. package/lib/Utils/validate-connection.d.ts +11 -0
  299. package/lib/Utils/validate-connection.d.ts.map +1 -0
  300. package/lib/Utils/validate-connection.js +74 -104
  301. package/lib/Utils/validate-connection.js.map +1 -0
  302. package/lib/WABinary/constants.d.ts +28 -0
  303. package/lib/WABinary/constants.d.ts.map +1 -0
  304. package/lib/WABinary/constants.js +9 -11
  305. package/lib/WABinary/constants.js.map +1 -0
  306. package/lib/WABinary/decode.d.ts +7 -0
  307. package/lib/WABinary/decode.d.ts.map +1 -0
  308. package/lib/WABinary/decode.js +49 -52
  309. package/lib/WABinary/decode.js.map +1 -0
  310. package/lib/WABinary/encode.d.ts +3 -0
  311. package/lib/WABinary/encode.d.ts.map +1 -0
  312. package/lib/WABinary/encode.js +19 -49
  313. package/lib/WABinary/encode.js.map +1 -0
  314. package/lib/WABinary/generic-utils.d.ts +15 -0
  315. package/lib/WABinary/generic-utils.d.ts.map +1 -0
  316. package/lib/WABinary/generic-utils.js +46 -43
  317. package/lib/WABinary/generic-utils.js.map +1 -0
  318. package/lib/WABinary/index.d.ts +6 -0
  319. package/lib/WABinary/index.d.ts.map +1 -0
  320. package/lib/WABinary/index.js +6 -21
  321. package/lib/WABinary/index.js.map +1 -0
  322. package/lib/WABinary/jid-utils.d.ts +48 -0
  323. package/lib/WABinary/jid-utils.d.ts.map +1 -0
  324. package/lib/WABinary/jid-utils.js +72 -45
  325. package/lib/WABinary/jid-utils.js.map +1 -0
  326. package/lib/WABinary/types.d.ts +19 -0
  327. package/lib/WABinary/types.d.ts.map +1 -0
  328. package/lib/WABinary/types.js +2 -2
  329. package/lib/WABinary/types.js.map +1 -0
  330. package/lib/WAM/BinaryInfo.d.ts +9 -0
  331. package/lib/WAM/BinaryInfo.d.ts.map +1 -0
  332. package/lib/WAM/BinaryInfo.js +2 -5
  333. package/lib/WAM/BinaryInfo.js.map +1 -0
  334. package/lib/WAM/constants.d.ts +40 -0
  335. package/lib/WAM/constants.d.ts.map +1 -0
  336. package/lib/WAM/constants.js +19071 -11568
  337. package/lib/WAM/constants.js.map +1 -0
  338. package/lib/WAM/encode.d.ts +3 -0
  339. package/lib/WAM/encode.d.ts.map +1 -0
  340. package/lib/WAM/encode.js +17 -22
  341. package/lib/WAM/encode.js.map +1 -0
  342. package/lib/WAM/index.d.ts +4 -0
  343. package/lib/WAM/index.d.ts.map +1 -0
  344. package/lib/WAM/index.js +4 -19
  345. package/lib/WAM/index.js.map +1 -0
  346. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
  347. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts.map +1 -0
  348. package/lib/WAUSync/Protocols/USyncContactProtocol.js +33 -13
  349. package/lib/WAUSync/Protocols/USyncContactProtocol.js.map +1 -0
  350. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
  351. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts.map +1 -0
  352. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -14
  353. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js.map +1 -0
  354. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
  355. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts.map +1 -0
  356. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +8 -11
  357. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js.map +1 -0
  358. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
  359. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts.map +1 -0
  360. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -13
  361. package/lib/WAUSync/Protocols/USyncStatusProtocol.js.map +1 -0
  362. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +10 -0
  363. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts.map +1 -0
  364. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
  365. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js.map +1 -0
  366. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
  367. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts.map +1 -0
  368. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -22
  369. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js.map +1 -0
  370. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
  371. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts.map +1 -0
  372. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -8
  373. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js.map +1 -0
  374. package/lib/WAUSync/Protocols/index.d.ts +6 -0
  375. package/lib/WAUSync/Protocols/index.d.ts.map +1 -0
  376. package/lib/WAUSync/Protocols/index.js +6 -20
  377. package/lib/WAUSync/Protocols/index.js.map +1 -0
  378. package/lib/WAUSync/USyncQuery.d.ts +30 -0
  379. package/lib/WAUSync/USyncQuery.d.ts.map +1 -0
  380. package/lib/WAUSync/USyncQuery.js +44 -35
  381. package/lib/WAUSync/USyncQuery.js.map +1 -0
  382. package/lib/WAUSync/USyncUser.d.ts +17 -0
  383. package/lib/WAUSync/USyncUser.d.ts.map +1 -0
  384. package/lib/WAUSync/USyncUser.js +10 -5
  385. package/lib/WAUSync/USyncUser.js.map +1 -0
  386. package/lib/WAUSync/index.d.ts +4 -0
  387. package/lib/WAUSync/index.d.ts.map +1 -0
  388. package/lib/WAUSync/index.js +4 -19
  389. package/lib/WAUSync/index.js.map +1 -0
  390. package/lib/index.d.ts +12 -0
  391. package/lib/index.d.ts.map +1 -0
  392. package/lib/index.js +11 -70
  393. package/lib/index.js.map +1 -0
  394. package/package.json +100 -60
@@ -1,549 +1,244 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.getStatusCodeForMediaRetry =
40
- exports.decryptMediaRetryData =
41
- exports.decodeMediaRetryNode =
42
- exports.encryptMediaRetryRequest =
43
- exports.getWAUploadToServer =
44
- exports.downloadEncryptedContent =
45
- exports.downloadContentFromMessage =
46
- exports.getUrlFromDirectPath =
47
- exports.encryptedStream =
48
- exports.prepareStream =
49
- exports.getHttpStream =
50
- exports.getStream =
51
- exports.toBuffer =
52
- exports.toReadable =
53
- exports.mediaMessageSHA256B64 =
54
- exports.generateProfilePicture =
55
- exports.encodeBase64EncodedStringForUpload =
56
- exports.extractImageThumb =
57
- exports.extractVideoThumb =
58
- exports.hkdfInfoKey = void 0;
59
- exports.getMediaKeys = getMediaKeys;
60
- exports.uploadFile = uploadFile;
61
- exports.vid2jpg = vid2jpg;
62
- exports.getAudioDuration = getAudioDuration;
63
- exports.getAudioWaveform = getAudioWaveform;
64
- exports.generateThumbnail = generateThumbnail;
65
- exports.extensionForMediaMessage = extensionForMediaMessage;
66
- // 🆅🆈🆉🅴🅽 🅱🅰🅸🅻
67
- const boom_1 = require("@hapi/boom");
68
- const axios_1 = __importDefault(require("axios"));
69
- const form_data_1 = __importDefault(require("form-data"));
70
- const cheerio = __importStar(require("cheerio"));
71
- const Crypto = __importStar(require("crypto"));
72
- const events_1 = require("events");
73
- const fs_1 = require("fs");
74
- const os_1 = require("os");
75
- const path_1 = require("path");
76
- const jimp_1 = __importDefault(require("jimp"));
77
- const stream_1 = require("stream");
78
- const child_process_1 = require("child_process");
79
- const WAProto_1 = require("../../WAProto");
80
- const Defaults_1 = require("../Defaults");
81
- const WABinary_1 = require("../WABinary");
82
- const crypto_1 = require("./crypto");
83
- const generics_1 = require("./generics");
84
- const getTmpFilesDirectory = () => (0, os_1.tmpdir)();
1
+ import { Boom } from '@hapi/boom';
2
+ import { exec } from 'child_process';
3
+ import * as Crypto from 'crypto';
4
+ import { once } from 'events';
5
+ import { createReadStream, createWriteStream, promises as fs, WriteStream } from 'fs';
6
+ import { tmpdir } from 'os';
7
+ import { join } from 'path';
8
+ import { Readable, Transform } from 'stream';
9
+ import { URL } from 'url';
10
+ import { proto } from '../../WAProto/index.js';
11
+ import { DEFAULT_ORIGIN, MEDIA_HKDF_KEY_MAPPING, MEDIA_PATH_MAP } from '../Defaults/index.js';
12
+ import { getBinaryNodeChild, getBinaryNodeChildBuffer, jidNormalizedUser } from '../WABinary/index.js';
13
+ import { aesDecryptGCM, aesEncryptGCM, hkdf } from './crypto.js';
14
+ import { generateMessageIDV2 } from './generics.js';
15
+ const getTmpFilesDirectory = () => tmpdir();
85
16
  const getImageProcessingLibrary = async () => {
86
- const [_jimp, sharp] = await Promise.all([
87
- (async () => {
88
- const jimp = await (Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => { }));
89
- return jimp;
90
- })(),
91
- (async () => {
92
- const sharp = await (Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => { }));
93
- return sharp;
94
- })()
95
- ]);
17
+ //@ts-ignore
18
+ const [jimp, sharp] = await Promise.all([import('jimp').catch(() => { }), import('sharp').catch(() => { })]);
96
19
  if (sharp) {
97
20
  return { sharp };
98
21
  }
99
- const jimp = (_jimp === null || _jimp === void 0 ? void 0 : _jimp.default) || _jimp;
100
22
  if (jimp) {
101
23
  return { jimp };
102
24
  }
103
- throw new boom_1.Boom('No image processing library available');
25
+ throw new Boom('No image processing library available');
104
26
  };
105
- const hkdfInfoKey = (type) => {
106
- const hkdfInfo = Defaults_1.MEDIA_HKDF_KEY_MAPPING[type];
27
+ export const hkdfInfoKey = (type) => {
28
+ const hkdfInfo = MEDIA_HKDF_KEY_MAPPING[type];
107
29
  return `WhatsApp ${hkdfInfo} Keys`;
108
30
  };
109
- exports.hkdfInfoKey = hkdfInfoKey;
31
+ export const getRawMediaUploadData = async (media, mediaType, logger) => {
32
+ const { stream } = await getStream(media);
33
+ logger?.debug('got stream for raw upload');
34
+ const hasher = Crypto.createHash('sha256');
35
+ const filePath = join(tmpdir(), mediaType + generateMessageIDV2());
36
+ const fileWriteStream = createWriteStream(filePath);
37
+ let fileLength = 0;
38
+ try {
39
+ for await (const data of stream) {
40
+ fileLength += data.length;
41
+ hasher.update(data);
42
+ if (!fileWriteStream.write(data)) {
43
+ await once(fileWriteStream, 'drain');
44
+ }
45
+ }
46
+ fileWriteStream.end();
47
+ await once(fileWriteStream, 'finish');
48
+ stream.destroy();
49
+ const fileSha256 = hasher.digest();
50
+ logger?.debug('hashed data for raw upload');
51
+ return {
52
+ filePath: filePath,
53
+ fileSha256,
54
+ fileLength
55
+ };
56
+ }
57
+ catch (error) {
58
+ fileWriteStream.destroy();
59
+ stream.destroy();
60
+ try {
61
+ await fs.unlink(filePath);
62
+ }
63
+ catch {
64
+ //
65
+ }
66
+ throw error;
67
+ }
68
+ };
110
69
  /** generates all the keys required to encrypt/decrypt & sign a media message */
111
- async function getMediaKeys(buffer, mediaType) {
70
+ export async function getMediaKeys(buffer, mediaType) {
112
71
  if (!buffer) {
113
- throw new boom_1.Boom('Cannot derive from empty media key');
72
+ throw new Boom('Cannot derive from empty media key');
114
73
  }
115
74
  if (typeof buffer === 'string') {
116
75
  buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64');
117
76
  }
118
77
  // expand using HKDF to 112 bytes, also pass in the relevant app info
119
- const expandedMediaKey = await (0, crypto_1.hkdf)(buffer, 112, { info: (0, exports.hkdfInfoKey)(mediaType) });
78
+ const expandedMediaKey = hkdf(buffer, 112, { info: hkdfInfoKey(mediaType) });
120
79
  return {
121
80
  iv: expandedMediaKey.slice(0, 16),
122
81
  cipherKey: expandedMediaKey.slice(16, 48),
123
- macKey: expandedMediaKey.slice(48, 80),
82
+ macKey: expandedMediaKey.slice(48, 80)
124
83
  };
125
84
  }
126
- async function uploadFile(buffer, logger) {
127
- const { fromBuffer } = await Promise.resolve().then(() => __importStar(require('file-type')));
128
- const fileType = await fromBuffer(buffer);
129
- if (!fileType)
130
- throw new Error("Failed to detect file type.");
131
- const { ext, mime } = fileType;
132
- const services = [
133
- {
134
- name: "catbox",
135
- url: "https://catbox.moe/user/api.php",
136
- buildForm: () => {
137
- const form = new form_data_1.default();
138
- form.append("fileToUpload", buffer, {
139
- filename: `file.${ext}`,
140
- contentType: mime || "application/octet-stream"
141
- });
142
- form.append("reqtype", "fileupload");
143
- return form;
144
- },
145
- parseResponse: res => res.data
146
- },
147
- {
148
- name: "pdi.moe",
149
- url: "https://scdn.pdi.moe/upload",
150
- buildForm: () => {
151
- const form = new form_data_1.default();
152
- form.append("file", buffer, {
153
- filename: `file.${ext}`,
154
- contentType: mime
155
- });
156
- return form;
157
- },
158
- parseResponse: res => res.data.result.url
159
- },
160
- {
161
- name: "qu.ax",
162
- url: "https://qu.ax/upload.php",
163
- buildForm: () => {
164
- const form = new form_data_1.default();
165
- form.append("files[]", buffer, {
166
- filename: `file.${ext}`,
167
- contentType: mime || "application/octet-stream"
168
- });
169
- return form;
170
- },
171
- parseResponse: res => {
172
- var _a, _b, _c;
173
- if (!((_c = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.url))
174
- throw new Error("Failed to get URL from qu.ax");
175
- return res.data.files[0].url;
176
- }
177
- },
178
- {
179
- name: "uguu.se",
180
- url: "https://uguu.se/upload.php",
181
- buildForm: () => {
182
- const form = new form_data_1.default();
183
- form.append("files[]", buffer, {
184
- filename: `file.${ext}`,
185
- contentType: mime || "application/octet-stream"
186
- });
187
- return form;
188
- },
189
- parseResponse: res => {
190
- var _a, _b, _c;
191
- if (!((_c = (_b = (_a = res.data) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.url))
192
- throw new Error("Failed to get URL from uguu.se");
193
- return res.data.files[0].url;
194
- }
195
- },
196
- {
197
- name: "tmpfiles",
198
- url: "https://tmpfiles.org/api/v1/upload",
199
- buildForm: () => {
200
- const form = new form_data_1.default();
201
- form.append("file", buffer, {
202
- filename: `file.${ext}`,
203
- contentType: mime
204
- });
205
- return form;
206
- },
207
- parseResponse: res => {
208
- const match = res.data.data.url.match(/https:\/\/tmpfiles\.org\/(.*)/);
209
- if (!match)
210
- throw new Error("Failed to parse tmpfiles URL.");
211
- return `https://tmpfiles.org/dl/${match[1]}`;
212
- }
213
- }
214
- ];
215
- for (const service of services) {
216
- try {
217
- const form = service.buildForm();
218
- const res = await axios_1.default.post(service.url, form, {
219
- headers: form.getHeaders()
220
- });
221
- const url = service.parseResponse(res);
222
- return url;
223
- }
224
- catch (error) {
225
- logger === null || logger === void 0 ? void 0 : logger.debug(`[${service.name}] eror:`, (error === null || error === void 0 ? void 0 : error.message) || error);
226
- }
227
- }
228
- throw new Error("All upload services failed.");
229
- }
230
- async function vid2jpg(videoUrl) {
231
- try {
232
- const { data } = await axios_1.default.get(`https://ezgif.com/video-to-jpg?url=${encodeURIComponent(videoUrl)}`);
233
- const $ = cheerio.load(data);
234
- const fileToken = $('input[name="file"]').attr("value");
235
- if (!fileToken) {
236
- throw new Error("Failed to retrieve file token. The video URL may be invalid or inaccessible.");
85
+ /** Extracts video thumb using FFMPEG */
86
+ const extractVideoThumb = async (path, destPath, time, size) => new Promise((resolve, reject) => {
87
+ const cmd = `ffmpeg -ss ${time} -i ${path} -y -vf scale=${size.width}:-1 -vframes 1 -f image2 ${destPath}`;
88
+ exec(cmd, err => {
89
+ if (err) {
90
+ reject(err);
237
91
  }
238
- const formData = new URLSearchParams();
239
- formData.append("file", fileToken);
240
- formData.append("end", "1");
241
- formData.append("video-to-jpg", "Convert to JPG!");
242
- const convert = await axios_1.default.post(`https://ezgif.com/video-to-jpg/${fileToken}`, formData);
243
- const $2 = cheerio.load(convert.data);
244
- let imageUrl = $2("#output img").first().attr("src");
245
- if (!imageUrl) {
246
- throw new Error("Could not locate the converted image output.");
247
- }
248
- if (imageUrl.startsWith("//")) {
249
- imageUrl = "https:" + imageUrl;
250
- }
251
- else if (imageUrl.startsWith("/")) {
252
- const cdnMatch = imageUrl.match(/\/(s\d+\..+?)\/.*/);
253
- if (cdnMatch) {
254
- imageUrl = "https://" + imageUrl.slice(2);
255
- }
256
- else {
257
- imageUrl = "https://ezgif.com" + imageUrl;
258
- }
92
+ else {
93
+ resolve();
259
94
  }
260
- return imageUrl;
261
- }
262
- catch (error) {
263
- throw new Error("Failed to convert video to JPG: " + error.message);
264
- }
265
- }
266
- /**
267
- * Extracts video thumbnail using FFmpeg
268
- */
269
- const extractVideoThumb = async (videoPath, time = '00:00:00', size = { width: 256 }) => {
270
- return new Promise((resolve, reject) => {
271
- const args = [
272
- '-ss', time,
273
- '-i', videoPath,
274
- '-y',
275
- '-vf', `scale=${size.width}:-1`,
276
- '-vframes', '1',
277
- '-f', 'image2',
278
- '-vcodec', 'mjpeg',
279
- 'pipe:1'
280
- ];
281
- const ffmpeg = (0, child_process_1.spawn)('ffmpeg', args);
282
- const chunks = [];
283
- let errorOutput = '';
284
- ffmpeg.stdout.on('data', chunk => chunks.push(chunk));
285
- ffmpeg.stderr.on('data', data => {
286
- errorOutput += data.toString();
287
- });
288
- ffmpeg.on('error', reject);
289
- ffmpeg.on('close', code => {
290
- if (code === 0) return resolve(Buffer.concat(chunks));
291
- reject(new Error(`ffmpeg exited with code ${code}\n${errorOutput}`));
292
- });
293
95
  });
294
- };
295
- exports.extractVideoThumb = extractVideoThumb;
296
- const extractImageThumb = async (bufferOrFilePath, width = 32) => {
297
- var _a, _b;
298
- if (bufferOrFilePath instanceof stream_1.Readable) {
299
- bufferOrFilePath = await (0, exports.toBuffer)(bufferOrFilePath);
96
+ });
97
+ export const extractImageThumb = async (bufferOrFilePath, width = 32) => {
98
+ // TODO: Move entirely to sharp, removing jimp as it supports readable streams
99
+ // This will have positive speed and performance impacts as well as minimizing RAM usage.
100
+ if (bufferOrFilePath instanceof Readable) {
101
+ bufferOrFilePath = await toBuffer(bufferOrFilePath);
300
102
  }
301
103
  const lib = await getImageProcessingLibrary();
302
- if ('sharp' in lib && typeof ((_a = lib.sharp) === null || _a === void 0 ? void 0 : _a.default) === 'function') {
104
+ if ('sharp' in lib && typeof lib.sharp?.default === 'function') {
303
105
  const img = lib.sharp.default(bufferOrFilePath);
304
106
  const dimensions = await img.metadata();
305
- const buffer = await img
306
- .resize(width)
307
- .jpeg({ quality: 50 })
308
- .toBuffer();
107
+ const buffer = await img.resize(width).jpeg({ quality: 50 }).toBuffer();
309
108
  return {
310
109
  buffer,
311
110
  original: {
312
111
  width: dimensions.width,
313
- height: dimensions.height,
314
- },
112
+ height: dimensions.height
113
+ }
315
114
  };
316
115
  }
317
- else if ('jimp' in lib && typeof ((_b = lib.jimp) === null || _b === void 0 ? void 0 : _b.read) === 'function') {
318
- const { read, MIME_JPEG, RESIZE_BILINEAR, AUTO } = lib.jimp;
319
- const jimp = await read(bufferOrFilePath);
116
+ else if ('jimp' in lib && typeof lib.jimp?.Jimp === 'object') {
117
+ const jimp = await lib.jimp.Jimp.read(bufferOrFilePath);
320
118
  const dimensions = {
321
- width: jimp.getWidth(),
322
- height: jimp.getHeight()
119
+ width: jimp.width,
120
+ height: jimp.height
323
121
  };
324
122
  const buffer = await jimp
325
- .quality(50)
326
- .resize(width, AUTO, RESIZE_BILINEAR)
327
- .getBufferAsync(MIME_JPEG);
123
+ .resize({ w: width, mode: lib.jimp.ResizeStrategy.BILINEAR })
124
+ .getBuffer('image/jpeg', { quality: 50 });
328
125
  return {
329
126
  buffer,
330
127
  original: dimensions
331
128
  };
332
129
  }
333
130
  else {
334
- throw new boom_1.Boom('No image processing library available');
131
+ throw new Boom('No image processing library available');
335
132
  }
336
133
  };
337
- exports.extractImageThumb = extractImageThumb;
338
- const encodeBase64EncodedStringForUpload = (b64) => (encodeURIComponent(b64
339
- .replace(/\+/g, '-')
340
- .replace(/\//g, '_')
341
- .replace(/\=+$/, '')));
342
- exports.encodeBase64EncodedStringForUpload = encodeBase64EncodedStringForUpload;
343
- const generateProfilePicture = async (mediaUpload) => {
344
- let bufferOrFilePath;
345
- let img;
134
+ export const encodeBase64EncodedStringForUpload = (b64) => encodeURIComponent(b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, ''));
135
+ export const generateProfilePicture = async (mediaUpload, dimensions) => {
136
+ let buffer;
137
+ const { width: w = 640, height: h = 640 } = dimensions || {};
346
138
  if (Buffer.isBuffer(mediaUpload)) {
347
- bufferOrFilePath = mediaUpload;
139
+ buffer = mediaUpload;
348
140
  }
349
- else if ('url' in mediaUpload) {
350
- bufferOrFilePath = mediaUpload.url.toString();
141
+ else {
142
+ // Use getStream to handle all WAMediaUpload types (Buffer, Stream, URL)
143
+ const { stream } = await getStream(mediaUpload);
144
+ // Convert the resulting stream to a buffer
145
+ buffer = await toBuffer(stream);
146
+ }
147
+ const lib = await getImageProcessingLibrary();
148
+ let img;
149
+ if ('sharp' in lib && typeof lib.sharp?.default === 'function') {
150
+ img = lib.sharp
151
+ .default(buffer)
152
+ .resize(w, h)
153
+ .jpeg({
154
+ quality: 50
155
+ })
156
+ .toBuffer();
157
+ }
158
+ else if ('jimp' in lib && typeof lib.jimp?.Jimp === 'function') {
159
+ const jimp = await lib.jimp.Jimp.read(buffer);
160
+ const min = Math.min(jimp.width, jimp.height);
161
+ const cropped = jimp.crop({ x: 0, y: 0, w: min, h: min });
162
+ img = cropped.resize({ w, h, mode: lib.jimp.ResizeStrategy.BILINEAR }).getBuffer('image/jpeg', { quality: 50 });
351
163
  }
352
164
  else {
353
- bufferOrFilePath = await (0, exports.toBuffer)(mediaUpload.stream);
165
+ throw new Boom('No image processing library available');
354
166
  }
355
- const jimp = await jimp_1.default.read(bufferOrFilePath);
356
- const cropped = jimp.getWidth() > jimp.getHeight() ? jimp.resize(550, -1) : jimp.resize(-1, 650);
357
- img = cropped
358
- .quality(100)
359
- .getBufferAsync(jimp_1.default.MIME_JPEG);
360
167
  return {
361
- img: await img,
168
+ img: await img
362
169
  };
363
170
  };
364
- exports.generateProfilePicture = generateProfilePicture;
365
171
  /** gets the SHA256 of the given media message */
366
- const mediaMessageSHA256B64 = (message) => {
172
+ export const mediaMessageSHA256B64 = (message) => {
367
173
  const media = Object.values(message)[0];
368
- return (media === null || media === void 0 ? void 0 : media.fileSha256) && Buffer.from(media.fileSha256).toString('base64');
174
+ return media?.fileSha256 && Buffer.from(media.fileSha256).toString('base64');
369
175
  };
370
- exports.mediaMessageSHA256B64 = mediaMessageSHA256B64;
371
- async function getAudioDuration(buffer) {
372
- try {
373
- const { PassThrough } = require('stream');
374
- const ff = require('fluent-ffmpeg');
375
-
376
- return await new Promise((resolve, reject) => {
377
- const inputStream = new PassThrough();
378
- inputStream.end(buffer);
379
-
380
- ff(inputStream)
381
- .ffprobe((err, data) => {
382
- if (err) reject(err);
383
- else resolve(data.format.duration);
384
- });
385
- });
386
- } catch (error) {
387
- const musicMetadata = await import('music-metadata');
388
- let metadata;
389
- if (Buffer.isBuffer(buffer)) {
390
- metadata = await musicMetadata.parseBuffer(buffer, undefined, {
391
- duration: true
392
- });
393
- } else if (typeof buffer === 'string') {
394
- const rStream = (0, fs_1.createReadStream)(buffer);
395
- try {
396
- metadata = await musicMetadata.parseStream(rStream, undefined, {
397
- duration: true
398
- });
399
- } finally {
400
- rStream.destroy();
401
- }
402
- } else {
403
- metadata = await musicMetadata.parseStream(buffer, undefined, {
404
- duration: true
405
- });
406
- }
407
- return metadata.format.duration;
176
+ export async function getAudioDuration(buffer) {
177
+ const musicMetadata = await import('music-metadata');
178
+ let metadata;
179
+ const options = {
180
+ duration: true
181
+ };
182
+ if (Buffer.isBuffer(buffer)) {
183
+ metadata = await musicMetadata.parseBuffer(buffer, undefined, options);
184
+ }
185
+ else if (typeof buffer === 'string') {
186
+ metadata = await musicMetadata.parseFile(buffer, options);
408
187
  }
188
+ else {
189
+ metadata = await musicMetadata.parseStream(buffer, undefined, options);
190
+ }
191
+ return metadata.format.duration;
409
192
  }
410
- exports.getAudioDuration = getAudioDuration;
411
- async function getAudioWaveform(buffer, logger) {
193
+ /**
194
+ referenced from and modifying https://github.com/wppconnect-team/wa-js/blob/main/src/chat/functions/prepareAudioWaveform.ts
195
+ */
196
+ export async function getAudioWaveform(buffer, logger) {
412
197
  try {
413
- const { PassThrough } = require('stream');
414
- const ff = require('fluent-ffmpeg');
415
-
198
+ // @ts-ignore
199
+ const { default: decoder } = await import('audio-decode');
416
200
  let audioData;
417
201
  if (Buffer.isBuffer(buffer)) {
418
202
  audioData = buffer;
419
- } else if (typeof buffer === 'string') {
420
- const rStream = require('fs').createReadStream(buffer);
421
- audioData = await exports.toBuffer(rStream);
422
- } else {
423
- audioData = await exports.toBuffer(buffer);
424
203
  }
425
-
426
- return await new Promise((resolve, reject) => {
427
- const inputStream = new PassThrough();
428
- inputStream.end(audioData);
429
- const chunks = [];
430
- const bars = 64;
431
-
432
- ff(inputStream)
433
- .audioChannels(1)
434
- .audioFrequency(16000)
435
- .format('s16le')
436
- .on('error', reject)
437
- .on('end', () => {
438
- const rawData = Buffer.concat(chunks);
439
- const samples = rawData.length / 2;
440
- const amplitudes = [];
441
-
442
- for (let i = 0; i < samples; i++) {
443
- amplitudes.push(Math.abs(rawData.readInt16LE(i * 2)) / 32768);
444
- }
445
-
446
- const blockSize = Math.floor(amplitudes.length / bars);
447
- const avg = [];
448
- for (let i = 0; i < bars; i++) {
449
- const block = amplitudes.slice(i * blockSize, (i + 1) * blockSize);
450
- avg.push(block.reduce((a, b) => a + b, 0) / block.length);
451
- }
452
-
453
- const max = Math.max(...avg);
454
- const normalized = avg.map(v => Math.floor((v / max) * 100));
455
- resolve(new Uint8Array(normalized));
456
- })
457
- .pipe()
458
- .on('data', chunk => chunks.push(chunk));
459
- });
460
- } catch (e) {
461
- logger?.debug(e);
462
- }
463
- }
464
- exports.getAudioWaveform = getAudioWaveform;
465
- async function convertToOpusBuffer(buffer, logger) {
466
- try {
467
- const { PassThrough } = require('stream');
468
- const ff = require('fluent-ffmpeg');
469
-
470
- return await new Promise((resolve, reject) => {
471
- const inStream = new PassThrough();
472
- const outStream = new PassThrough();
473
- const chunks = [];
474
- inStream.end(buffer);
475
-
476
- ff(inStream)
477
- .noVideo()
478
- .audioCodec('libopus')
479
- .format('ogg')
480
- .audioBitrate('48k')
481
- .audioChannels(1)
482
- .audioFrequency(48000)
483
- .outputOptions([
484
- '-vn',
485
- '-b:a 64k',
486
- '-ac 2',
487
- '-ar 48000',
488
- '-map_metadata', '-1',
489
- '-application', 'voip'
490
- ])
491
- .on('error', reject)
492
- .on('end', () => resolve(Buffer.concat(chunks)))
493
- .pipe(outStream, {
494
- end: true
495
- });
496
- outStream.on('data', c => chunks.push(c));
497
- });
498
- } catch (e) {
499
- logger?.debug(e);
500
- throw e;
204
+ else if (typeof buffer === 'string') {
205
+ const rStream = createReadStream(buffer);
206
+ audioData = await toBuffer(rStream);
207
+ }
208
+ else {
209
+ audioData = await toBuffer(buffer);
210
+ }
211
+ const audioBuffer = await decoder(audioData);
212
+ const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data
213
+ const samples = 64; // Number of samples we want to have in our final data set
214
+ const blockSize = Math.floor(rawData.length / samples); // the number of samples in each subdivision
215
+ const filteredData = [];
216
+ for (let i = 0; i < samples; i++) {
217
+ const blockStart = blockSize * i; // the location of the first sample in the block
218
+ let sum = 0;
219
+ for (let j = 0; j < blockSize; j++) {
220
+ sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block
221
+ }
222
+ filteredData.push(sum / blockSize); // divide the sum by the block size to get the average
223
+ }
224
+ // This guarantees that the largest data point will be set to 1, and the rest of the data will scale proportionally.
225
+ const multiplier = Math.pow(Math.max(...filteredData), -1);
226
+ const normalizedData = filteredData.map(n => n * multiplier);
227
+ // Generate waveform like WhatsApp
228
+ const waveform = new Uint8Array(normalizedData.map(n => Math.floor(100 * n)));
229
+ return waveform;
501
230
  }
502
- }
503
- exports.convertToOpusBuffer = convertToOpusBuffer;
504
- async function convertToMp4Buffer(buffer, logger) {
505
- try {
506
- const { PassThrough } = require('stream');
507
- const ff = require('fluent-ffmpeg');
508
-
509
- return await new Promise((resolve, reject) => {
510
- const inStream = new PassThrough();
511
- const outStream = new PassThrough();
512
- const chunks = [];
513
-
514
- inStream.end(buffer);
515
-
516
- ff(inStream)
517
- .videoCodec('libx264')
518
- .audioCodec('aac')
519
- .format('mp4')
520
- .outputOptions([
521
- '-preset', 'veryfast',
522
- '-crf', '23',
523
- '-movflags', 'faststart',
524
- '-map_metadata', '-1'
525
- ])
526
- .on('error', reject)
527
- .on('end', () => resolve(Buffer.concat(chunks)))
528
- .pipe(outStream, { end: true });
529
-
530
- outStream.on('data', c => chunks.push(c));
531
- });
532
- } catch (e) {
533
- logger?.debug(e);
534
- throw e;
231
+ catch (e) {
232
+ logger?.debug('Failed to generate waveform: ' + e);
535
233
  }
536
234
  }
537
-
538
- exports.convertToMp4Buffer = convertToMp4Buffer;
539
- const toReadable = (buffer) => {
540
- const readable = new stream_1.Readable({ read: () => { } });
235
+ export const toReadable = (buffer) => {
236
+ const readable = new Readable({ read: () => { } });
541
237
  readable.push(buffer);
542
238
  readable.push(null);
543
239
  return readable;
544
240
  };
545
- exports.toReadable = toReadable;
546
- const toBuffer = async (stream) => {
241
+ export const toBuffer = async (stream) => {
547
242
  const chunks = [];
548
243
  for await (const chunk of stream) {
549
244
  chunks.push(chunk);
@@ -551,61 +246,47 @@ const toBuffer = async (stream) => {
551
246
  stream.destroy();
552
247
  return Buffer.concat(chunks);
553
248
  };
554
- exports.toBuffer = toBuffer;
555
- const getStream = async (item, opts) => {
249
+ export const getStream = async (item, opts) => {
556
250
  if (Buffer.isBuffer(item)) {
557
- return { stream: (0, exports.toReadable)(item), type: 'buffer' };
251
+ return { stream: toReadable(item), type: 'buffer' };
558
252
  }
559
253
  if ('stream' in item) {
560
254
  return { stream: item.stream, type: 'readable' };
561
255
  }
562
- if (item.url.toString().startsWith('http://') || item.url.toString().startsWith('https://')) {
563
- return { stream: await (0, exports.getHttpStream)(item.url, opts), type: 'remote' };
256
+ const urlStr = item.url.toString();
257
+ if (urlStr.startsWith('data:')) {
258
+ const buffer = Buffer.from(urlStr.split(',')[1], 'base64');
259
+ return { stream: toReadable(buffer), type: 'buffer' };
564
260
  }
565
- return { stream: (0, fs_1.createReadStream)(item.url), type: 'file' };
261
+ if (urlStr.startsWith('http://') || urlStr.startsWith('https://')) {
262
+ return { stream: await getHttpStream(item.url, opts), type: 'remote' };
263
+ }
264
+ return { stream: createReadStream(item.url), type: 'file' };
566
265
  };
567
- exports.getStream = getStream;
568
266
  /** generates a thumbnail for a given media, if required */
569
- async function generateThumbnail(file, mediaType, options) {
570
- var _a;
267
+ export async function generateThumbnail(file, mediaType, options) {
571
268
  let thumbnail;
572
269
  let originalImageDimensions;
573
270
  if (mediaType === 'image') {
574
- const { buffer, original } = await (0, exports.extractImageThumb)(file);
271
+ const { buffer, original } = await extractImageThumb(file);
575
272
  thumbnail = buffer.toString('base64');
576
273
  if (original.width && original.height) {
577
274
  originalImageDimensions = {
578
275
  width: original.width,
579
- height: original.height,
276
+ height: original.height
580
277
  };
581
278
  }
582
279
  }
583
280
  else if (mediaType === 'video') {
281
+ const imgFilename = join(getTmpFilesDirectory(), generateMessageIDV2() + '.jpg');
584
282
  try {
585
- let videoPath = file;
586
- if (Buffer.isBuffer(file) || file instanceof stream_1.Readable) {
587
- videoPath = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.mp4');
588
- const buffer = Buffer.isBuffer(file) ? file : await (0, exports.toBuffer)(file);
589
- await fs_1.promises.writeFile(videoPath, buffer);
590
- }
591
- const thumbnailBuffer = await (0, exports.extractVideoThumb)(videoPath);
592
- const imgFilename = (0, path_1.join)(getTmpFilesDirectory(), (0, generics_1.generateMessageIDV2)() + '.jpg');
593
- await fs_1.promises.writeFile(imgFilename, thumbnailBuffer);
594
- const { buffer: processedThumbnailBuffer, original } = await (0, exports.extractImageThumb)(imgFilename);
595
- thumbnail = processedThumbnailBuffer.toString('base64');
596
- if (original.width && original.height) {
597
- originalImageDimensions = {
598
- width: original.width,
599
- height: original.height,
600
- };
601
- }
602
- await fs_1.promises.unlink(imgFilename);
603
- if (videoPath !== file) {
604
- await fs_1.promises.unlink(videoPath);
605
- }
283
+ await extractVideoThumb(file, imgFilename, '00:00:00', { width: 32, height: 32 });
284
+ const buff = await fs.readFile(imgFilename);
285
+ thumbnail = buff.toString('base64');
286
+ await fs.unlink(imgFilename);
606
287
  }
607
288
  catch (err) {
608
- (_a = options.logger) === null || _a === void 0 ? void 0 : _a.debug('could not generate video thumb: ' + err);
289
+ options.logger?.debug('could not generate video thumb: ' + err);
609
290
  }
610
291
  }
611
292
  return {
@@ -613,196 +294,145 @@ async function generateThumbnail(file, mediaType, options) {
613
294
  originalImageDimensions
614
295
  };
615
296
  }
616
- const getHttpStream = async (url, options = {}) => {
617
- const fetched = await axios_1.default.get(url.toString(), { ...options, responseType: 'stream' });
618
- return fetched.data;
619
- };
620
- exports.getHttpStream = getHttpStream;
621
- const prepareStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
622
- const { stream, type } = await (0, exports.getStream)(media, opts);
623
- logger === null || logger === void 0 ? void 0 : logger.debug('fetched media stream');
624
- let bodyPath;
625
- let didSaveToTmpPath = false;
626
- try {
627
- const buffer = await (0, exports.toBuffer)(stream);
628
- if (type === 'file') {
629
- bodyPath = media.url;
630
- }
631
- else if (saveOriginalFileIfRequired) {
632
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
633
- (0, fs_1.writeFileSync)(bodyPath, buffer);
634
- didSaveToTmpPath = true;
635
- }
636
- const fileLength = buffer.length;
637
- const fileSha256 = Crypto.createHash('sha256').update(buffer).digest();
638
- stream === null || stream === void 0 ? void 0 : stream.destroy();
639
- logger === null || logger === void 0 ? void 0 : logger.debug('prepare stream data successfully');
640
- return {
641
- mediaKey: undefined,
642
- encWriteStream: buffer,
643
- fileLength,
644
- fileSha256,
645
- fileEncSha256: undefined,
646
- bodyPath,
647
- didSaveToTmpPath
648
- };
649
- }
650
- catch (error) {
651
- stream.destroy();
652
- if (didSaveToTmpPath) {
653
- try {
654
- await fs_1.promises.unlink(bodyPath);
655
- }
656
- catch (err) {
657
- logger === null || logger === void 0 ? void 0 : logger.error({ err }, 'failed to save to tmp path');
658
- }
659
- }
660
- throw error;
297
+ export const getHttpStream = async (url, options = {}) => {
298
+ const response = await fetch(url.toString(), {
299
+ dispatcher: options.dispatcher,
300
+ method: 'GET',
301
+ headers: options.headers
302
+ });
303
+ if (!response.ok) {
304
+ throw new Boom(`Failed to fetch stream from ${url}`, { statusCode: response.status, data: { url } });
661
305
  }
306
+ // @ts-ignore Node18+ Readable.fromWeb exists
307
+ return response.body instanceof Readable ? response.body : Readable.fromWeb(response.body);
662
308
  };
663
- exports.prepareStream = prepareStream;
664
- const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts, isPtt, forceOpus, convertVideo } = {}) => {
665
- const { stream, type } = await (0, exports.getStream)(media, opts);
309
+ export const encryptedStream = async (media, mediaType, { logger, saveOriginalFileIfRequired, opts } = {}) => {
310
+ const { stream, type } = await getStream(media, opts);
666
311
  logger?.debug('fetched media stream');
667
-
668
- let finalStream = stream;
669
-
670
- if (mediaType === 'audio' && (isPtt === true || forceOpus === true)) {
671
- try {
672
- const buffer = await (0, exports.toBuffer)(stream);
673
- const opusBuffer = await exports.convertToOpusBuffer(buffer, logger);
674
- finalStream = (0, exports.toReadable)(opusBuffer);
675
- logger?.debug('converted audio to Opus');
676
- } catch (error) {
677
- logger?.error('failed to convert audio to Opus, fallback to original stream');
678
- const { stream: newStream } = await (0, exports.getStream)(media, opts);
679
- finalStream = newStream;
680
- }
681
- }
682
-
683
- if (mediaType === 'video' && convertVideo === true) {
684
- try {
685
- const buffer = await (0, exports.toBuffer)(stream);
686
- const mp4Buffer = await exports.convertToMp4Buffer(buffer, logger);
687
- finalStream = (0, exports.toReadable)(mp4Buffer);
688
- logger?.debug('converted video to mp4');
689
- } catch (error) {
690
- logger?.error('failed to convert video to mp4, fallback to original stream');
691
- const { stream: newStream } = await (0, exports.getStream)(media, opts);
692
- finalStream = newStream;
693
- }
694
- }
695
-
696
312
  const mediaKey = Crypto.randomBytes(32);
697
313
  const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
698
- const encWriteStream = new stream_1.Readable({ read: () => {} });
699
- let bodyPath;
700
- let writeStream;
701
- let didSaveToTmpPath = false;
702
-
703
- if (type === 'file') {
704
- bodyPath = media.url;
705
- } else if (saveOriginalFileIfRequired) {
706
- bodyPath = (0, path_1.join)(getTmpFilesDirectory(), mediaType + (0, generics_1.generateMessageIDV2)());
707
- writeStream = (0, fs_1.createWriteStream)(bodyPath);
708
- didSaveToTmpPath = true;
314
+ const encFilePath = join(getTmpFilesDirectory(), mediaType + generateMessageIDV2() + '-enc');
315
+ const encFileWriteStream = createWriteStream(encFilePath);
316
+ let originalFileStream;
317
+ let originalFilePath;
318
+ if (saveOriginalFileIfRequired) {
319
+ originalFilePath = join(getTmpFilesDirectory(), mediaType + generateMessageIDV2() + '-original');
320
+ originalFileStream = createWriteStream(originalFilePath);
709
321
  }
710
-
711
322
  let fileLength = 0;
712
323
  const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv);
713
- let hmac = Crypto.createHmac('sha256', macKey).update(iv);
714
- let sha256Plain = Crypto.createHash('sha256');
715
- let sha256Enc = Crypto.createHash('sha256');
716
-
324
+ const hmac = Crypto.createHmac('sha256', macKey).update(iv);
325
+ const sha256Plain = Crypto.createHash('sha256');
326
+ const sha256Enc = Crypto.createHash('sha256');
327
+ const onChunk = async (buff) => {
328
+ sha256Enc.update(buff);
329
+ hmac.update(buff);
330
+ // Handle backpressure: if write returns false, wait for drain
331
+ if (!encFileWriteStream.write(buff)) {
332
+ await once(encFileWriteStream, 'drain');
333
+ }
334
+ };
717
335
  try {
718
- for await (const data of finalStream) {
336
+ for await (const data of stream) {
719
337
  fileLength += data.length;
720
- if (type === 'remote' && (opts?.maxContentLength) && fileLength + data.length > opts.maxContentLength) {
721
- throw new boom_1.Boom(`content length exceeded when encrypting "${type}"`, { data: { media, type } });
338
+ if (type === 'remote' &&
339
+ opts?.maxContentLength &&
340
+ fileLength + data.length > opts.maxContentLength) {
341
+ throw new Boom(`content length exceeded when encrypting "${type}"`, {
342
+ data: { media, type }
343
+ });
722
344
  }
723
-
724
- sha256Plain = sha256Plain.update(data);
725
-
726
- if (writeStream) {
727
- if (!writeStream.write(data)) {
728
- await (0, events_1.once)(writeStream, 'drain');
345
+ if (originalFileStream) {
346
+ if (!originalFileStream.write(data)) {
347
+ await once(originalFileStream, 'drain');
729
348
  }
730
349
  }
731
-
732
- onChunk(aes.update(data));
350
+ sha256Plain.update(data);
351
+ await onChunk(aes.update(data));
733
352
  }
734
-
735
- onChunk(aes.final());
353
+ await onChunk(aes.final());
736
354
  const mac = hmac.digest().slice(0, 10);
737
- sha256Enc = sha256Enc.update(mac);
355
+ sha256Enc.update(mac);
738
356
  const fileSha256 = sha256Plain.digest();
739
357
  const fileEncSha256 = sha256Enc.digest();
740
-
741
- encWriteStream.push(mac);
742
- encWriteStream.push(null);
743
- writeStream?.end();
744
- finalStream.destroy();
745
-
358
+ encFileWriteStream.write(mac);
359
+ const encFinishPromise = once(encFileWriteStream, 'finish');
360
+ const originalFinishPromise = originalFileStream ? once(originalFileStream, 'finish') : Promise.resolve();
361
+ encFileWriteStream.end();
362
+ originalFileStream?.end?.();
363
+ stream.destroy();
364
+ // Wait for write streams to fully flush to disk
365
+ // This helps reduce memory pressure by allowing OS to release buffers
366
+ await encFinishPromise;
367
+ await originalFinishPromise;
746
368
  logger?.debug('encrypted data successfully');
747
-
748
369
  return {
749
370
  mediaKey,
750
- encWriteStream,
751
- bodyPath,
371
+ originalFilePath,
372
+ encFilePath,
752
373
  mac,
753
374
  fileEncSha256,
754
375
  fileSha256,
755
- fileLength,
756
- didSaveToTmpPath
376
+ fileLength
757
377
  };
758
- } catch (error) {
759
- encWriteStream.destroy();
760
- writeStream?.destroy();
378
+ }
379
+ catch (error) {
380
+ // destroy all streams with error
381
+ encFileWriteStream.destroy();
382
+ originalFileStream?.destroy?.();
761
383
  aes.destroy();
762
384
  hmac.destroy();
763
385
  sha256Plain.destroy();
764
386
  sha256Enc.destroy();
765
- finalStream.destroy();
766
-
767
- if (didSaveToTmpPath) {
768
- try {
769
- await fs_1.promises.unlink(bodyPath);
770
- } catch (err) {
771
- logger?.error({ err }, 'failed to save to tmp path');
387
+ stream.destroy();
388
+ try {
389
+ await fs.unlink(encFilePath);
390
+ if (originalFilePath) {
391
+ await fs.unlink(originalFilePath);
772
392
  }
773
393
  }
394
+ catch (err) {
395
+ logger?.error({ err }, 'failed deleting tmp files');
396
+ }
774
397
  throw error;
775
398
  }
776
-
777
- function onChunk(buff) {
778
- sha256Enc = sha256Enc.update(buff);
779
- hmac = hmac.update(buff);
780
- encWriteStream.push(buff);
781
- }
782
399
  };
783
-
784
- exports.encryptedStream = encryptedStream;
785
- const DEF_HOST = 'mmg.whatsapp.net';
400
+ export const DEF_MEDIA_HOST = 'mmg.whatsapp.net';
786
401
  const AES_CHUNK_SIZE = 16;
787
402
  const toSmallestChunkSize = (num) => {
788
403
  return Math.floor(num / AES_CHUNK_SIZE) * AES_CHUNK_SIZE;
789
404
  };
790
- const getUrlFromDirectPath = (directPath) => `https://${DEF_HOST}${directPath}`;
791
- exports.getUrlFromDirectPath = getUrlFromDirectPath;
792
- const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
793
- const isValidMediaUrl = url === null || url === void 0 ? void 0 : url.startsWith('https://mmg.whatsapp.net/');
794
- const downloadUrl = isValidMediaUrl ? url : (0, exports.getUrlFromDirectPath)(directPath);
405
+ export const getUrlFromDirectPath = (directPath, host = DEF_MEDIA_HOST) => `https://${host}${directPath}`;
406
+ const extractHost = (url) => {
407
+ if (!url)
408
+ return undefined;
409
+ try {
410
+ return new URL(url).host;
411
+ }
412
+ catch {
413
+ return undefined;
414
+ }
415
+ };
416
+ export const downloadContentFromMessage = async ({ mediaKey, directPath, url }, type, opts = {}) => {
417
+ // Fallback host: explicit opt > host parsed from `url` > DEF_MEDIA_HOST.
418
+ // Lets us honor a non-default host carried by the proto without forcing callers to thread it through.
419
+ const fallbackHost = opts.host ?? extractHost(url);
420
+ const downloadUrl = directPath ? getUrlFromDirectPath(directPath, fallbackHost) : url;
795
421
  if (!downloadUrl) {
796
- throw new boom_1.Boom('No valid media URL or directPath present in message', { statusCode: 400 });
422
+ throw new Boom('No valid media URL or directPath present in message', { statusCode: 400 });
797
423
  }
798
424
  const keys = await getMediaKeys(mediaKey, type);
799
- return (0, exports.downloadEncryptedContent)(downloadUrl, keys, opts);
425
+ return downloadEncryptedContent(downloadUrl, keys, opts);
800
426
  };
801
- exports.downloadContentFromMessage = downloadContentFromMessage;
802
- const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
427
+ /**
428
+ * Decrypts and downloads an AES256-CBC encrypted file given the keys.
429
+ * Assumes the SHA256 of the plaintext is appended to the end of the ciphertext
430
+ * */
431
+ export const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startByte, endByte, options } = {}) => {
803
432
  let bytesFetched = 0;
804
433
  let startChunk = 0;
805
434
  let firstBlockIsIV = false;
435
+ // if a start byte is specified -- then we need to fetch the previous chunk as that will form the IV
806
436
  if (startByte) {
807
437
  const chunk = toSmallestChunkSize(startByte || 0);
808
438
  if (chunk) {
@@ -812,9 +442,14 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
812
442
  }
813
443
  }
814
444
  const endChunk = endByte ? toSmallestChunkSize(endByte || 0) + AES_CHUNK_SIZE : undefined;
445
+ const headersInit = options?.headers ? options.headers : undefined;
815
446
  const headers = {
816
- ...(options === null || options === void 0 ? void 0 : options.headers) || {},
817
- Origin: Defaults_1.DEFAULT_ORIGIN,
447
+ ...(headersInit
448
+ ? Array.isArray(headersInit)
449
+ ? Object.fromEntries(headersInit)
450
+ : headersInit
451
+ : {}),
452
+ Origin: DEFAULT_ORIGIN
818
453
  };
819
454
  if (startChunk || endChunk) {
820
455
  headers.Range = `bytes=${startChunk}-`;
@@ -822,11 +457,10 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
822
457
  headers.Range += endChunk;
823
458
  }
824
459
  }
825
- const fetched = await (0, exports.getHttpStream)(downloadUrl, {
826
- ...options || {},
827
- headers,
828
- maxBodyLength: Infinity,
829
- maxContentLength: Infinity,
460
+ // download the message
461
+ const fetched = await getHttpStream(downloadUrl, {
462
+ ...(options || {}),
463
+ headers
830
464
  });
831
465
  let remainingBytes = Buffer.from([]);
832
466
  let aes;
@@ -841,9 +475,9 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
841
475
  push(bytes);
842
476
  }
843
477
  };
844
- const output = new stream_1.Transform({
478
+ const output = new Transform({
845
479
  transform(chunk, _, callback) {
846
- let data = Buffer.concat([remainingBytes, chunk]);
480
+ let data = remainingBytes.length ? Buffer.concat([remainingBytes, chunk]) : chunk;
847
481
  const decryptLength = toSmallestChunkSize(data.length);
848
482
  remainingBytes = data.slice(decryptLength);
849
483
  data = data.slice(0, decryptLength);
@@ -854,6 +488,8 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
854
488
  data = data.slice(AES_CHUNK_SIZE);
855
489
  }
856
490
  aes = Crypto.createDecipheriv('aes-256-cbc', cipherKey, ivValue);
491
+ // if an end byte that is not EOF is specified
492
+ // stop auto padding (PKCS7) -- otherwise throws an error for decryption
857
493
  if (endByte) {
858
494
  aes.setAutoPadding(false);
859
495
  }
@@ -874,18 +510,15 @@ const downloadEncryptedContent = async (downloadUrl, { cipherKey, iv }, { startB
874
510
  catch (error) {
875
511
  callback(error);
876
512
  }
877
- },
513
+ }
878
514
  });
879
515
  return fetched.pipe(output, { end: true });
880
516
  };
881
- exports.downloadEncryptedContent = downloadEncryptedContent;
882
- function extensionForMediaMessage(message) {
883
- const getExtension = (mimetype) => mimetype.split(';')[0].split('/')[1];
517
+ export function extensionForMediaMessage(message) {
518
+ const getExtension = (mimetype) => mimetype.split(';')[0]?.split('/')[1];
884
519
  const type = Object.keys(message)[0];
885
520
  let extension;
886
- if (type === 'locationMessage' ||
887
- type === 'liveLocationMessage' ||
888
- type === 'productMessage') {
521
+ if (type === 'locationMessage' || type === 'liveLocationMessage' || type === 'productMessage') {
889
522
  extension = '.jpeg';
890
523
  }
891
524
  else {
@@ -894,52 +527,158 @@ function extensionForMediaMessage(message) {
894
527
  }
895
528
  return extension;
896
529
  }
897
- const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
898
- return async (stream, { mediaType, fileEncSha256B64, newsletter, timeoutMs }) => {
899
- var _a, _b;
530
+ const isNodeRuntime = () => {
531
+ return (typeof process !== 'undefined' &&
532
+ process.versions?.node !== null &&
533
+ typeof process.versions.bun === 'undefined' &&
534
+ typeof globalThis.Deno === 'undefined');
535
+ };
536
+ export const uploadWithNodeHttp = async ({ url, filePath, headers, timeoutMs, agent }, redirectCount = 0) => {
537
+ if (redirectCount > 5) {
538
+ throw new Error('Too many redirects');
539
+ }
540
+ const parsedUrl = new URL(url);
541
+ const httpModule = parsedUrl.protocol === 'https:' ? await import('https') : await import('http');
542
+ // Get file size for Content-Length header (required for Node.js streaming)
543
+ const fileStats = await fs.stat(filePath);
544
+ const fileSize = fileStats.size;
545
+ return new Promise((resolve, reject) => {
546
+ const req = httpModule.request({
547
+ hostname: parsedUrl.hostname,
548
+ port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
549
+ path: parsedUrl.pathname + parsedUrl.search,
550
+ method: 'POST',
551
+ headers: {
552
+ ...headers,
553
+ 'Content-Length': fileSize
554
+ },
555
+ agent,
556
+ timeout: timeoutMs
557
+ }, res => {
558
+ // Handle redirects (3xx)
559
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
560
+ res.resume(); // Consume response to free resources
561
+ const newUrl = new URL(res.headers.location, url).toString();
562
+ resolve(uploadWithNodeHttp({
563
+ url: newUrl,
564
+ filePath,
565
+ headers,
566
+ timeoutMs,
567
+ agent
568
+ }, redirectCount + 1));
569
+ return;
570
+ }
571
+ let body = '';
572
+ res.on('data', chunk => (body += chunk));
573
+ res.on('end', () => {
574
+ try {
575
+ resolve(JSON.parse(body));
576
+ }
577
+ catch {
578
+ resolve(undefined);
579
+ }
580
+ });
581
+ });
582
+ req.on('error', reject);
583
+ req.on('timeout', () => {
584
+ req.destroy();
585
+ reject(new Error('Upload timeout'));
586
+ });
587
+ const stream = createReadStream(filePath);
588
+ stream.pipe(req);
589
+ stream.on('error', err => {
590
+ req.destroy();
591
+ reject(err);
592
+ });
593
+ });
594
+ };
595
+ const uploadWithFetch = async ({ url, filePath, headers, timeoutMs, agent }) => {
596
+ // Convert Node.js Readable to Web ReadableStream
597
+ const nodeStream = createReadStream(filePath);
598
+ const webStream = Readable.toWeb(nodeStream);
599
+ // Native fetch only accepts Undici-style dispatchers, not generic https Agents.
600
+ const dispatcher = typeof agent?.dispatch === 'function' ? agent : undefined;
601
+ const response = await fetch(url, {
602
+ ...(dispatcher ? { dispatcher } : {}),
603
+ method: 'POST',
604
+ body: webStream,
605
+ headers,
606
+ duplex: 'half',
607
+ signal: timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined
608
+ });
609
+ try {
610
+ return (await response.json());
611
+ }
612
+ catch {
613
+ return undefined;
614
+ }
615
+ };
616
+ /**
617
+ * Uploads media to WhatsApp servers.
618
+ *
619
+ * ## Why we have two upload implementations:
620
+ *
621
+ * Node.js's native `fetch` (powered by undici) has a known bug where it buffers
622
+ * the entire request body in memory before sending, even when using streams.
623
+ * This causes memory issues with large files (e.g., 1GB file = 1GB+ memory usage).
624
+ * See: https://github.com/nodejs/undici/issues/4058
625
+ *
626
+ * Other runtimes (Bun, Deno, browsers) correctly stream the request body without
627
+ * buffering, so we can use the web-standard Fetch API there.
628
+ *
629
+ * ## Future considerations:
630
+ * Once the undici bug is fixed, we can simplify this to use only the Fetch API
631
+ * across all runtimes. Monitor the GitHub issue for updates.
632
+ */
633
+ const uploadMedia = async (params, logger) => {
634
+ if (isNodeRuntime()) {
635
+ logger?.debug('Using Node.js https module for upload (avoids undici buffering bug)');
636
+ return uploadWithNodeHttp(params);
637
+ }
638
+ else {
639
+ logger?.debug('Using web-standard Fetch API for upload');
640
+ return uploadWithFetch(params);
641
+ }
642
+ };
643
+ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options }, refreshMediaConn) => {
644
+ return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => {
645
+ // send a query JSON to obtain the url & auth token to upload our media
900
646
  let uploadInfo = await refreshMediaConn(false);
901
647
  let urls;
902
648
  const hosts = [...customUploadHosts, ...uploadInfo.hosts];
903
- const chunks = [];
904
- if (!Buffer.isBuffer(stream)) {
905
- for await (const chunk of stream) {
906
- chunks.push(chunk);
907
- }
908
- }
909
- const reqBody = Buffer.isBuffer(stream) ? stream : Buffer.concat(chunks);
910
- fileEncSha256B64 = (0, exports.encodeBase64EncodedStringForUpload)(fileEncSha256B64);
911
- let media = Defaults_1.MEDIA_PATH_MAP[mediaType];
912
- if (newsletter) {
913
- media = media === null || media === void 0 ? void 0 : media.replace('/mms/', '/newsletter/newsletter-');
914
- }
915
- for (const { hostname, maxContentLengthBytes } of hosts) {
649
+ fileEncSha256B64 = encodeBase64EncodedStringForUpload(fileEncSha256B64);
650
+ // Prepare common headers
651
+ const customHeaders = (() => {
652
+ const hdrs = options?.headers;
653
+ if (!hdrs)
654
+ return {};
655
+ return Array.isArray(hdrs) ? Object.fromEntries(hdrs) : hdrs;
656
+ })();
657
+ const headers = {
658
+ ...customHeaders,
659
+ 'Content-Type': 'application/octet-stream',
660
+ Origin: DEFAULT_ORIGIN
661
+ };
662
+ for (const { hostname } of hosts) {
916
663
  logger.debug(`uploading to "${hostname}"`);
917
664
  const auth = encodeURIComponent(uploadInfo.auth);
918
- const url = `https://${hostname}${media}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
665
+ const url = `https://${hostname}${MEDIA_PATH_MAP[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
919
666
  let result;
920
667
  try {
921
- if (maxContentLengthBytes && reqBody.length > maxContentLengthBytes) {
922
- throw new boom_1.Boom(`Body too large for "${hostname}"`, { statusCode: 413 });
923
- }
924
- const body = await axios_1.default.post(url, reqBody, {
925
- ...options,
926
- headers: {
927
- ...options.headers || {},
928
- 'Content-Type': 'application/octet-stream',
929
- 'Origin': Defaults_1.DEFAULT_ORIGIN
930
- },
931
- httpsAgent: fetchAgent,
932
- timeout: timeoutMs,
933
- responseType: 'json',
934
- maxBodyLength: Infinity,
935
- maxContentLength: Infinity,
936
- });
937
- result = body.data;
938
- if ((result === null || result === void 0 ? void 0 : result.url) || (result === null || result === void 0 ? void 0 : result.directPath)) {
668
+ result = await uploadMedia({
669
+ url,
670
+ filePath,
671
+ headers,
672
+ timeoutMs,
673
+ agent: fetchAgent
674
+ }, logger);
675
+ if (result?.url || result?.direct_path) {
939
676
  urls = {
940
677
  mediaUrl: result.url,
941
678
  directPath: result.direct_path,
942
- handle: result.handle
679
+ meta_hmac: result.meta_hmac,
680
+ fbid: result.fbid,
681
+ ts: result.ts
943
682
  };
944
683
  break;
945
684
  }
@@ -949,37 +688,39 @@ const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger, options },
949
688
  }
950
689
  }
951
690
  catch (error) {
952
- if (axios_1.default.isAxiosError(error)) {
953
- result = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
954
- }
955
- const isLast = hostname === ((_b = hosts[uploadInfo.hosts.length - 1]) === null || _b === void 0 ? void 0 : _b.hostname);
956
- logger.warn({ trace: error.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
691
+ const isLast = hostname === hosts[uploadInfo.hosts.length - 1]?.hostname;
692
+ logger.warn({ trace: error?.stack, uploadResult: result }, `Error in uploading to ${hostname} ${isLast ? '' : ', retrying...'}`);
957
693
  }
958
694
  }
959
695
  if (!urls) {
960
- throw new boom_1.Boom('Media upload failed on all hosts', { statusCode: 500 });
696
+ throw new Boom('Media upload failed on all hosts', { statusCode: 500 });
961
697
  }
962
698
  return urls;
963
699
  };
964
700
  };
965
- exports.getWAUploadToServer = getWAUploadToServer;
966
701
  const getMediaRetryKey = (mediaKey) => {
967
- return (0, crypto_1.hkdf)(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
702
+ return hkdf(mediaKey, 32, { info: 'WhatsApp Media Retry Notification' });
968
703
  };
969
- const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
704
+ /**
705
+ * Generate a binary node that will request the phone to re-upload the media & return the newly uploaded URL
706
+ */
707
+ export const encryptMediaRetryRequest = (key, mediaKey, meId) => {
970
708
  const recp = { stanzaId: key.id };
971
- const recpBuffer = WAProto_1.proto.ServerErrorReceipt.encode(recp).finish();
709
+ const recpBuffer = proto.ServerErrorReceipt.encode(recp).finish();
972
710
  const iv = Crypto.randomBytes(12);
973
- const retryKey = await getMediaRetryKey(mediaKey);
974
- const ciphertext = (0, crypto_1.aesEncryptGCM)(recpBuffer, retryKey, iv, Buffer.from(key.id));
711
+ const retryKey = getMediaRetryKey(mediaKey);
712
+ const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id));
975
713
  const req = {
976
714
  tag: 'receipt',
977
715
  attrs: {
978
716
  id: key.id,
979
- to: (0, WABinary_1.jidNormalizedUser)(meId),
717
+ to: jidNormalizedUser(meId),
980
718
  type: 'server-error'
981
719
  },
982
720
  content: [
721
+ // this encrypt node is actually pretty useless
722
+ // the media is returned even without this node
723
+ // keeping it here to maintain parity with WA Web
983
724
  {
984
725
  tag: 'encrypt',
985
726
  attrs: {},
@@ -992,7 +733,8 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
992
733
  tag: 'rmr',
993
734
  attrs: {
994
735
  jid: key.remoteJid,
995
- 'from_me': (!!key.fromMe).toString(),
736
+ from_me: (!!key.fromMe).toString(),
737
+ // @ts-ignore
996
738
  participant: key.participant || undefined
997
739
  }
998
740
  }
@@ -1000,9 +742,8 @@ const encryptMediaRetryRequest = async (key, mediaKey, meId) => {
1000
742
  };
1001
743
  return req;
1002
744
  };
1003
- exports.encryptMediaRetryRequest = encryptMediaRetryRequest;
1004
- const decodeMediaRetryNode = (node) => {
1005
- const rmrNode = (0, WABinary_1.getBinaryNodeChild)(node, 'rmr');
745
+ export const decodeMediaRetryNode = (node) => {
746
+ const rmrNode = getBinaryNodeChild(node, 'rmr');
1006
747
  const event = {
1007
748
  key: {
1008
749
  id: node.attrs.id,
@@ -1011,39 +752,37 @@ const decodeMediaRetryNode = (node) => {
1011
752
  participant: rmrNode.attrs.participant
1012
753
  }
1013
754
  };
1014
- const errorNode = (0, WABinary_1.getBinaryNodeChild)(node, 'error');
755
+ const errorNode = getBinaryNodeChild(node, 'error');
1015
756
  if (errorNode) {
1016
757
  const errorCode = +errorNode.attrs.code;
1017
- event.error = new boom_1.Boom(`Failed to re-upload media (${errorCode})`, { data: errorNode.attrs, statusCode: (0, exports.getStatusCodeForMediaRetry)(errorCode) });
758
+ event.error = new Boom(`Failed to re-upload media (${errorCode})`, {
759
+ data: errorNode.attrs,
760
+ statusCode: getStatusCodeForMediaRetry(errorCode)
761
+ });
1018
762
  }
1019
763
  else {
1020
- const encryptedInfoNode = (0, WABinary_1.getBinaryNodeChild)(node, 'encrypt');
1021
- const ciphertext = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_p');
1022
- const iv = (0, WABinary_1.getBinaryNodeChildBuffer)(encryptedInfoNode, 'enc_iv');
764
+ const encryptedInfoNode = getBinaryNodeChild(node, 'encrypt');
765
+ const ciphertext = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_p');
766
+ const iv = getBinaryNodeChildBuffer(encryptedInfoNode, 'enc_iv');
1023
767
  if (ciphertext && iv) {
1024
768
  event.media = { ciphertext, iv };
1025
769
  }
1026
770
  else {
1027
- event.error = new boom_1.Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
771
+ event.error = new Boom('Failed to re-upload media (missing ciphertext)', { statusCode: 404 });
1028
772
  }
1029
773
  }
1030
774
  return event;
1031
775
  };
1032
- exports.decodeMediaRetryNode = decodeMediaRetryNode;
1033
- const decryptMediaRetryData = async ({ ciphertext, iv }, mediaKey, msgId) => {
1034
- const retryKey = await getMediaRetryKey(mediaKey);
1035
- const plaintext = (0, crypto_1.aesDecryptGCM)(ciphertext, retryKey, iv, Buffer.from(msgId));
1036
- return WAProto_1.proto.MediaRetryNotification.decode(plaintext);
776
+ export const decryptMediaRetryData = ({ ciphertext, iv }, mediaKey, msgId) => {
777
+ const retryKey = getMediaRetryKey(mediaKey);
778
+ const plaintext = aesDecryptGCM(ciphertext, retryKey, iv, Buffer.from(msgId));
779
+ return proto.MediaRetryNotification.decode(plaintext);
1037
780
  };
1038
- exports.decryptMediaRetryData = decryptMediaRetryData;
1039
- const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
1040
- exports.getStatusCodeForMediaRetry = getStatusCodeForMediaRetry;
781
+ export const getStatusCodeForMediaRetry = (code) => MEDIA_RETRY_STATUS_MAP[code];
1041
782
  const MEDIA_RETRY_STATUS_MAP = {
1042
- [WAProto_1.proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
1043
- [WAProto_1.proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
1044
- [WAProto_1.proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
1045
- [WAProto_1.proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418,
783
+ [proto.MediaRetryNotification.ResultType.SUCCESS]: 200,
784
+ [proto.MediaRetryNotification.ResultType.DECRYPTION_ERROR]: 412,
785
+ [proto.MediaRetryNotification.ResultType.NOT_FOUND]: 404,
786
+ [proto.MediaRetryNotification.ResultType.GENERAL_ERROR]: 418
1046
787
  };
1047
- function __importStar(arg0) {
1048
- throw new Error('Function not implemented.');
1049
- }
788
+ //# sourceMappingURL=messages-media.js.map