@fer2809fl/baileys 1.4.9 → 7.0.0

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