@japofc/baileys 2.1.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 (342) hide show
  1. package/NOTICE.md +111 -0
  2. package/README.md +1254 -0
  3. package/WAProto/index.d.ts +9 -0
  4. package/WAProto/index.js +142276 -0
  5. package/engine-requirements.js +13 -0
  6. package/lib/Builders/A2UI.d.ts +242 -0
  7. package/lib/Builders/A2UI.js +308 -0
  8. package/lib/Builders/AIRich.d.ts +105 -0
  9. package/lib/Builders/AIRich.js +2286 -0
  10. package/lib/Builders/Button.d.ts +103 -0
  11. package/lib/Builders/Button.js +883 -0
  12. package/lib/Builders/ButtonV2.d.ts +28 -0
  13. package/lib/Builders/ButtonV2.js +144 -0
  14. package/lib/Builders/ButtonV3.d.ts +25 -0
  15. package/lib/Builders/ButtonV3.js +184 -0
  16. package/lib/Builders/Carousel.d.ts +22 -0
  17. package/lib/Builders/Carousel.js +111 -0
  18. package/lib/Builders/JapBaileys.d.ts +34 -0
  19. package/lib/Builders/JapBaileys.js +108 -0
  20. package/lib/Builders/Poll.d.ts +25 -0
  21. package/lib/Builders/Poll.js +128 -0
  22. package/lib/Builders/index.d.ts +17 -0
  23. package/lib/Builders/index.js +11 -0
  24. package/lib/Builders/shared.d.ts +67 -0
  25. package/lib/Builders/shared.js +652 -0
  26. package/lib/Defaults/index.d.ts +154 -0
  27. package/lib/Defaults/index.js +178 -0
  28. package/lib/Framework/Bot.d.ts +61 -0
  29. package/lib/Framework/Bot.js +248 -0
  30. package/lib/Framework/Context.d.ts +21 -0
  31. package/lib/Framework/Context.js +89 -0
  32. package/lib/Framework/MediaManager.d.ts +17 -0
  33. package/lib/Framework/MediaManager.js +151 -0
  34. package/lib/Framework/SessionManager.d.ts +13 -0
  35. package/lib/Framework/SessionManager.js +33 -0
  36. package/lib/Framework/StatsManager.d.ts +26 -0
  37. package/lib/Framework/StatsManager.js +119 -0
  38. package/lib/Framework/Store/SQLiteStore.d.ts +11 -0
  39. package/lib/Framework/Store/SQLiteStore.js +73 -0
  40. package/lib/Framework/index.d.ts +9 -0
  41. package/lib/Framework/index.js +10 -0
  42. package/lib/Signal/Group/ciphertext-message.d.ts +9 -0
  43. package/lib/Signal/Group/ciphertext-message.js +11 -0
  44. package/lib/Signal/Group/group-session-builder.d.ts +7 -0
  45. package/lib/Signal/Group/group-session-builder.js +29 -0
  46. package/lib/Signal/Group/group_cipher.d.ts +10 -0
  47. package/lib/Signal/Group/group_cipher.js +81 -0
  48. package/lib/Signal/Group/index.d.ts +11 -0
  49. package/lib/Signal/Group/index.js +11 -0
  50. package/lib/Signal/Group/keyhelper.d.ts +6 -0
  51. package/lib/Signal/Group/keyhelper.js +17 -0
  52. package/lib/Signal/Group/sender-chain-key.d.ts +13 -0
  53. package/lib/Signal/Group/sender-chain-key.js +25 -0
  54. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -0
  55. package/lib/Signal/Group/sender-key-distribution-message.js +62 -0
  56. package/lib/Signal/Group/sender-key-message.d.ts +18 -0
  57. package/lib/Signal/Group/sender-key-message.js +65 -0
  58. package/lib/Signal/Group/sender-key-name.d.ts +11 -0
  59. package/lib/Signal/Group/sender-key-name.js +47 -0
  60. package/lib/Signal/Group/sender-key-record.d.ts +12 -0
  61. package/lib/Signal/Group/sender-key-record.js +40 -0
  62. package/lib/Signal/Group/sender-key-state.d.ts +16 -0
  63. package/lib/Signal/Group/sender-key-state.js +83 -0
  64. package/lib/Signal/Group/sender-message-key.d.ts +11 -0
  65. package/lib/Signal/Group/sender-message-key.js +25 -0
  66. package/lib/Signal/libsignal.d.ts +54 -0
  67. package/lib/Signal/libsignal.js +430 -0
  68. package/lib/Signal/lid-mapping.d.ts +20 -0
  69. package/lib/Signal/lid-mapping.js +276 -0
  70. package/lib/Socket/Client/index.d.ts +2 -0
  71. package/lib/Socket/Client/index.js +2 -0
  72. package/lib/Socket/Client/types.d.ts +5 -0
  73. package/lib/Socket/Client/types.js +10 -0
  74. package/lib/Socket/Client/websocket.d.ts +12 -0
  75. package/lib/Socket/Client/websocket.js +53 -0
  76. package/lib/Socket/business.d.ts +395 -0
  77. package/lib/Socket/business.js +379 -0
  78. package/lib/Socket/chats.d.ts +136 -0
  79. package/lib/Socket/chats.js +1327 -0
  80. package/lib/Socket/communities.d.ts +562 -0
  81. package/lib/Socket/communities.js +439 -0
  82. package/lib/Socket/dugong.d.ts +117 -0
  83. package/lib/Socket/dugong.js +798 -0
  84. package/lib/Socket/groups.d.ts +285 -0
  85. package/lib/Socket/groups.js +354 -0
  86. package/lib/Socket/index.d.ts +585 -0
  87. package/lib/Socket/index.js +52 -0
  88. package/lib/Socket/messages-recv.d.ts +333 -0
  89. package/lib/Socket/messages-recv.js +1781 -0
  90. package/lib/Socket/messages-send.d.ts +353 -0
  91. package/lib/Socket/messages-send.js +1524 -0
  92. package/lib/Socket/mex.d.ts +1 -0
  93. package/lib/Socket/mex.js +41 -0
  94. package/lib/Socket/newsletter.d.ts +286 -0
  95. package/lib/Socket/newsletter.js +364 -0
  96. package/lib/Socket/socket.d.ts +60 -0
  97. package/lib/Socket/socket.js +1012 -0
  98. package/lib/Socket/username.d.ts +82 -0
  99. package/lib/Socket/username.js +159 -0
  100. package/lib/Store/index.d.ts +3 -0
  101. package/lib/Store/index.js +3 -0
  102. package/lib/Store/make-in-memory-store.d.ts +62 -0
  103. package/lib/Store/make-in-memory-store.js +428 -0
  104. package/lib/Store/make-ordered-dictionary.d.ts +12 -0
  105. package/lib/Store/make-ordered-dictionary.js +78 -0
  106. package/lib/Store/object-repository.d.ts +10 -0
  107. package/lib/Store/object-repository.js +23 -0
  108. package/lib/Types/Auth.d.ts +117 -0
  109. package/lib/Types/Auth.js +1 -0
  110. package/lib/Types/Bussines.d.ts +25 -0
  111. package/lib/Types/Call.d.ts +15 -0
  112. package/lib/Types/Call.js +1 -0
  113. package/lib/Types/Chat.d.ts +124 -0
  114. package/lib/Types/Chat.js +7 -0
  115. package/lib/Types/Contact.d.ts +26 -0
  116. package/lib/Types/Contact.js +1 -0
  117. package/lib/Types/Events.d.ts +256 -0
  118. package/lib/Types/Events.js +1 -0
  119. package/lib/Types/GroupMetadata.d.ts +71 -0
  120. package/lib/Types/GroupMetadata.js +1 -0
  121. package/lib/Types/Label.d.ts +5 -0
  122. package/lib/Types/Label.js +24 -0
  123. package/lib/Types/LabelAssociation.d.ts +6 -0
  124. package/lib/Types/LabelAssociation.js +6 -0
  125. package/lib/Types/Message.d.ts +62 -0
  126. package/lib/Types/Message.js +17 -0
  127. package/lib/Types/Mex.d.ts +2 -0
  128. package/lib/Types/Mex.js +38 -0
  129. package/lib/Types/Product.d.ts +79 -0
  130. package/lib/Types/Product.js +1 -0
  131. package/lib/Types/RichType.d.ts +2 -0
  132. package/lib/Types/RichType.js +22 -0
  133. package/lib/Types/Signal.d.ts +87 -0
  134. package/lib/Types/Signal.js +1 -0
  135. package/lib/Types/Socket.d.ts +138 -0
  136. package/lib/Types/Socket.js +1 -0
  137. package/lib/Types/State.d.ts +8 -0
  138. package/lib/Types/State.js +55 -0
  139. package/lib/Types/USync.d.ts +26 -0
  140. package/lib/Types/index.d.ts +68 -0
  141. package/lib/Types/index.js +27 -0
  142. package/lib/Utils/MessageBuilder.d.ts +2 -0
  143. package/lib/Utils/MessageBuilder.js +2 -0
  144. package/lib/Utils/PersistentStore.d.ts +60 -0
  145. package/lib/Utils/PersistentStore.js +592 -0
  146. package/lib/Utils/anti-delete.d.ts +74 -0
  147. package/lib/Utils/anti-delete.js +221 -0
  148. package/lib/Utils/auth-secure.d.ts +86 -0
  149. package/lib/Utils/auth-secure.js +764 -0
  150. package/lib/Utils/auth-utils.d.ts +57 -0
  151. package/lib/Utils/auth-utils.js +306 -0
  152. package/lib/Utils/auto-reply.d.ts +47 -0
  153. package/lib/Utils/auto-reply.js +157 -0
  154. package/lib/Utils/baileys-event-stream.d.ts +8 -0
  155. package/lib/Utils/baileys-event-stream.js +62 -0
  156. package/lib/Utils/browser-utils.d.ts +8 -0
  157. package/lib/Utils/browser-utils.js +27 -0
  158. package/lib/Utils/business.d.ts +49 -0
  159. package/lib/Utils/business.js +239 -0
  160. package/lib/Utils/button-helper-utils.d.ts +53 -0
  161. package/lib/Utils/button-helper-utils.js +312 -0
  162. package/lib/Utils/button-sender.d.ts +54 -0
  163. package/lib/Utils/button-sender.js +822 -0
  164. package/lib/Utils/chat-control.d.ts +159 -0
  165. package/lib/Utils/chat-control.js +230 -0
  166. package/lib/Utils/chat-history-helpers.d.ts +21 -0
  167. package/lib/Utils/chat-history-helpers.js +70 -0
  168. package/lib/Utils/chat-utils.d.ts +407 -0
  169. package/lib/Utils/chat-utils.js +885 -0
  170. package/lib/Utils/companion-reg-client-utils.d.ts +4 -0
  171. package/lib/Utils/companion-reg-client-utils.js +39 -0
  172. package/lib/Utils/crypto.d.ts +41 -0
  173. package/lib/Utils/crypto.js +147 -0
  174. package/lib/Utils/decode-wa-message.d.ts +83 -0
  175. package/lib/Utils/decode-wa-message.js +316 -0
  176. package/lib/Utils/event-buffer.d.ts +12 -0
  177. package/lib/Utils/event-buffer.js +635 -0
  178. package/lib/Utils/generics.d.ts +69 -0
  179. package/lib/Utils/generics.js +438 -0
  180. package/lib/Utils/history-share.d.ts +11 -0
  181. package/lib/Utils/history-share.js +70 -0
  182. package/lib/Utils/history.d.ts +90 -0
  183. package/lib/Utils/history.js +146 -0
  184. package/lib/Utils/humanizer.d.ts +12 -0
  185. package/lib/Utils/humanizer.js +73 -0
  186. package/lib/Utils/identity-change-handler.d.ts +13 -0
  187. package/lib/Utils/identity-change-handler.js +49 -0
  188. package/lib/Utils/index.d.ts +57 -0
  189. package/lib/Utils/index.js +56 -0
  190. package/lib/Utils/jid-tools.d.ts +6 -0
  191. package/lib/Utils/jid-tools.js +77 -0
  192. package/lib/Utils/link-preview.d.ts +12 -0
  193. package/lib/Utils/link-preview.js +84 -0
  194. package/lib/Utils/logger.d.ts +4 -0
  195. package/lib/Utils/logger.js +2 -0
  196. package/lib/Utils/lt-hash.d.ts +12 -0
  197. package/lib/Utils/lt-hash.js +26 -0
  198. package/lib/Utils/make-mutex.d.ts +6 -0
  199. package/lib/Utils/make-mutex.js +32 -0
  200. package/lib/Utils/media-messages.d.ts +18 -0
  201. package/lib/Utils/media-messages.js +70 -0
  202. package/lib/Utils/media-set.d.ts +13 -0
  203. package/lib/Utils/media-set.js +171 -0
  204. package/lib/Utils/message-kind.d.ts +32 -0
  205. package/lib/Utils/message-kind.js +136 -0
  206. package/lib/Utils/message-retry-manager.d.ts +79 -0
  207. package/lib/Utils/message-retry-manager.js +264 -0
  208. package/lib/Utils/message-search.d.ts +44 -0
  209. package/lib/Utils/message-search.js +188 -0
  210. package/lib/Utils/messages-media.d.ts +135 -0
  211. package/lib/Utils/messages-media.js +868 -0
  212. package/lib/Utils/messages.d.ts +44 -0
  213. package/lib/Utils/messages.js +2326 -0
  214. package/lib/Utils/meta-ai.d.ts +13 -0
  215. package/lib/Utils/meta-ai.js +74 -0
  216. package/lib/Utils/mini-app.d.ts +35 -0
  217. package/lib/Utils/mini-app.js +213 -0
  218. package/lib/Utils/noise-handler.d.ts +20 -0
  219. package/lib/Utils/noise-handler.js +200 -0
  220. package/lib/Utils/offline-node-processor.d.ts +9 -0
  221. package/lib/Utils/offline-node-processor.js +39 -0
  222. package/lib/Utils/past-participants.d.ts +14 -0
  223. package/lib/Utils/past-participants.js +40 -0
  224. package/lib/Utils/pre-key-manager.d.ts +25 -0
  225. package/lib/Utils/pre-key-manager.js +105 -0
  226. package/lib/Utils/process-message.d.ts +82 -0
  227. package/lib/Utils/process-message.js +808 -0
  228. package/lib/Utils/qr-render.d.ts +59 -0
  229. package/lib/Utils/qr-render.js +179 -0
  230. package/lib/Utils/qrcodegen.d.ts +79 -0
  231. package/lib/Utils/qrcodegen.js +848 -0
  232. package/lib/Utils/reporting-utils.d.ts +12 -0
  233. package/lib/Utils/reporting-utils.js +257 -0
  234. package/lib/Utils/rich-message-utils.d.ts +48 -0
  235. package/lib/Utils/rich-message-utils.js +444 -0
  236. package/lib/Utils/router.d.ts +37 -0
  237. package/lib/Utils/router.js +165 -0
  238. package/lib/Utils/scheduled-posts.d.ts +30 -0
  239. package/lib/Utils/scheduled-posts.js +110 -0
  240. package/lib/Utils/scheduling.d.ts +42 -0
  241. package/lib/Utils/scheduling.js +139 -0
  242. package/lib/Utils/signal.d.ts +82 -0
  243. package/lib/Utils/signal.js +200 -0
  244. package/lib/Utils/stanza-ack.d.ts +16 -0
  245. package/lib/Utils/stanza-ack.js +37 -0
  246. package/lib/Utils/status.d.ts +50 -0
  247. package/lib/Utils/status.js +107 -0
  248. package/lib/Utils/stickerpack.d.ts +51 -0
  249. package/lib/Utils/stickerpack.js +274 -0
  250. package/lib/Utils/sync-action-utils.d.ts +2 -0
  251. package/lib/Utils/sync-action-utils.js +48 -0
  252. package/lib/Utils/tag.d.ts +12 -0
  253. package/lib/Utils/tag.js +44 -0
  254. package/lib/Utils/tc-token-utils.d.ts +29 -0
  255. package/lib/Utils/tc-token-utils.js +162 -0
  256. package/lib/Utils/templates.d.ts +76 -0
  257. package/lib/Utils/templates.js +150 -0
  258. package/lib/Utils/transcribe.d.ts +12 -0
  259. package/lib/Utils/transcribe.js +107 -0
  260. package/lib/Utils/use-cache-manager-auth-state.d.ts +13 -0
  261. package/lib/Utils/use-cache-manager-auth-state.js +81 -0
  262. package/lib/Utils/use-multi-file-auth-state.d.ts +10 -0
  263. package/lib/Utils/use-multi-file-auth-state.js +166 -0
  264. package/lib/Utils/use-single-file-auth-state.d.ts +10 -0
  265. package/lib/Utils/use-single-file-auth-state.js +113 -0
  266. package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
  267. package/lib/Utils/use-sqlite-auth-state.js +169 -0
  268. package/lib/Utils/validate-connection.d.ts +42 -0
  269. package/lib/Utils/validate-connection.js +198 -0
  270. package/lib/Utils/vcard.d.ts +58 -0
  271. package/lib/Utils/vcard.js +104 -0
  272. package/lib/Utils/voice-note.d.ts +15 -0
  273. package/lib/Utils/voice-note.js +63 -0
  274. package/lib/VoIP/audio-feeder.d.ts +18 -0
  275. package/lib/VoIP/audio-feeder.js +160 -0
  276. package/lib/VoIP/call-recorder.d.ts +13 -0
  277. package/lib/VoIP/call-recorder.js +73 -0
  278. package/lib/VoIP/index.d.ts +86 -0
  279. package/lib/VoIP/index.js +611 -0
  280. package/lib/VoIP/relay-transport.d.ts +43 -0
  281. package/lib/VoIP/relay-transport.js +563 -0
  282. package/lib/VoIP/signaling.d.ts +26 -0
  283. package/lib/VoIP/signaling.js +662 -0
  284. package/lib/VoIP/types.d.ts +69 -0
  285. package/lib/VoIP/types.js +17 -0
  286. package/lib/VoIP/wasm-engine.d.ts +120 -0
  287. package/lib/VoIP/wasm-engine.js +1358 -0
  288. package/lib/VoIP/worker-bootstrap.d.ts +4 -0
  289. package/lib/VoIP/worker-bootstrap.js +1046 -0
  290. package/lib/WABinary/constants.d.ts +61 -0
  291. package/lib/WABinary/constants.js +1466 -0
  292. package/lib/WABinary/decode.d.ts +9 -0
  293. package/lib/WABinary/decode.js +261 -0
  294. package/lib/WABinary/encode.d.ts +2 -0
  295. package/lib/WABinary/encode.js +219 -0
  296. package/lib/WABinary/generic-utils.d.ts +74 -0
  297. package/lib/WABinary/generic-utils.js +276 -0
  298. package/lib/WABinary/index.d.ts +5 -0
  299. package/lib/WABinary/index.js +5 -0
  300. package/lib/WABinary/jid-utils.d.ts +28 -0
  301. package/lib/WABinary/jid-utils.js +95 -0
  302. package/lib/WABinary/types.d.ts +19 -0
  303. package/lib/WABinary/types.js +1 -0
  304. package/lib/WAM/BinaryInfo.d.ts +7 -0
  305. package/lib/WAM/BinaryInfo.js +9 -0
  306. package/lib/WAM/constants.d.ts +34926 -0
  307. package/lib/WAM/constants.js +22852 -0
  308. package/lib/WAM/encode.d.ts +1 -0
  309. package/lib/WAM/encode.js +149 -0
  310. package/lib/WAM/index.d.ts +3 -0
  311. package/lib/WAM/index.js +3 -0
  312. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +36 -0
  313. package/lib/WAUSync/Protocols/USyncContactProtocol.js +51 -0
  314. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +29 -0
  315. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +62 -0
  316. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
  317. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
  318. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
  319. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
  320. package/lib/WAUSync/Protocols/USyncUsernameProtocol.d.ts +9 -0
  321. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +24 -0
  322. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +38 -0
  323. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -0
  324. package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +14 -0
  325. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
  326. package/lib/WAUSync/Protocols/index.d.ts +7 -0
  327. package/lib/WAUSync/Protocols/index.js +7 -0
  328. package/lib/WAUSync/USyncQuery.d.ts +20 -0
  329. package/lib/WAUSync/USyncQuery.js +121 -0
  330. package/lib/WAUSync/USyncUser.d.ts +16 -0
  331. package/lib/WAUSync/USyncUser.js +30 -0
  332. package/lib/WAUSync/index.d.ts +3 -0
  333. package/lib/WAUSync/index.js +3 -0
  334. package/lib/assets/wasm/loader.d.ts +5 -0
  335. package/lib/assets/wasm/loader.js +5 -0
  336. package/lib/assets/wasm/whatsapp.wasm +0 -0
  337. package/lib/assets/wasm/worker-modules.d.ts +5 -0
  338. package/lib/assets/wasm/worker-modules.js +273 -0
  339. package/lib/index.d.ts +18 -0
  340. package/lib/index.js +23 -0
  341. package/package.json +180 -0
  342. package/postinstall-banner.js +82 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * JAP@Add --- Type declarations for the Meta AI helper (experimental).
3
+ */
4
+ export interface AskMetaAIOptions {
5
+ timeoutMs?: number;
6
+ jid?: string;
7
+ }
8
+ export interface AskMetaAIResult {
9
+ sent: any;
10
+ reply: any;
11
+ text: string;
12
+ }
13
+ export declare const askMetaAI: (sock: any, prompt: string, opts?: AskMetaAIOptions) => Promise<AskMetaAIResult>;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * JAP@Add --- Meta AI chat helper (EXPERIMENTAL).
3
+ *
4
+ * Sends a prompt to Meta AI's official JID (`13135550002@c.us`, override via
5
+ * `opts.jid` — e.g. the newer `11111111111@bot`) and waits for its reply.
6
+ * This relies on Meta AI being available for the linked account/region —
7
+ * expect timeouts where Meta AI is not rolled out.
8
+ *
9
+ * ```js
10
+ * const { text } = await askMetaAI(sock, 'Jelaskan black hole!')
11
+ * // or: await sock.askMetaAI('...')
12
+ * ```
13
+ */
14
+ import { Boom } from '@hapi/boom';
15
+ import { META_AI_JID } from '../WABinary/index.js';
16
+ import { normalizeMessageContent } from './messages.js';
17
+ const extractReplyText = (webMessage) => {
18
+ if (!webMessage?.message) {
19
+ return '';
20
+ }
21
+ const content = normalizeMessageContent(webMessage.message);
22
+ return content?.conversation
23
+ || content?.extendedTextMessage?.text
24
+ || content?.imageMessage?.caption
25
+ || content?.videoMessage?.caption
26
+ || '';
27
+ };
28
+ /**
29
+ * Ask Meta AI something. Resolves `{ sent, reply, text }`.
30
+ * Rejects with 408 on timeout (default 60s).
31
+ */
32
+ export const askMetaAI = async (sock, prompt, { timeoutMs = 60000, jid = META_AI_JID } = {}) => {
33
+ if (!sock || typeof sock.sendMessage !== 'function' || typeof sock.ev?.on !== 'function') {
34
+ throw new Boom('askMetaAI(sock, ...) requires an active Baileys socket', { statusCode: 400 });
35
+ }
36
+ if (!prompt || typeof prompt !== 'string') {
37
+ throw new Boom('askMetaAI(prompt) requires a non-empty string', { statusCode: 400 });
38
+ }
39
+ const sent = await sock.sendMessage(jid, { text: prompt });
40
+ const sentId = sent?.key?.id;
41
+ const startedAt = Date.now();
42
+ return new Promise((resolve, reject) => {
43
+ const done = (fn) => (...args) => {
44
+ clearTimeout(timer);
45
+ try {
46
+ sock.ev.off('messages.upsert', onUpsert);
47
+ }
48
+ catch { }
49
+ fn(...args);
50
+ };
51
+ const timer = setTimeout(done(() => reject(new Boom('askMetaAI: timed out waiting for Meta AI reply', { statusCode: 408 }))), timeoutMs);
52
+ const succeed = done(resolve);
53
+ const onUpsert = ({ messages } = {}) => {
54
+ for (const m of messages || []) {
55
+ if (!m || m.key?.fromMe || m.key?.remoteJid !== jid || !m.message) {
56
+ continue;
57
+ }
58
+ // Ignore stale history replayed on (re)connect.
59
+ const msgMs = Number(m.messageTimestamp || 0) * 1000;
60
+ if (msgMs && msgMs < startedAt - 5000) {
61
+ continue;
62
+ }
63
+ // Prefer a reply that quotes our prompt; otherwise take the first fresh message.
64
+ const quotedId = m.message?.extendedTextMessage?.contextInfo?.stanzaId;
65
+ if (quotedId && sentId && quotedId !== sentId) {
66
+ continue;
67
+ }
68
+ succeed({ sent, reply: m, text: extractReplyText(m) });
69
+ return;
70
+ }
71
+ };
72
+ sock.ev.on('messages.upsert', onUpsert);
73
+ });
74
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * JAP@Add --- Type declarations for the Mini App sender.
3
+ */
4
+ export declare const MINI_APP_DEFAULT_BUTTON_TEXT: string;
5
+ export interface MiniAppFlowOptions {
6
+ id: string;
7
+ cta?: string;
8
+ screen?: string;
9
+ data?: any;
10
+ action?: string;
11
+ actionPayload?: any;
12
+ version?: string;
13
+ token?: string;
14
+ }
15
+ export interface MiniAppOptions {
16
+ title?: string;
17
+ body?: string;
18
+ text?: string;
19
+ url?: string;
20
+ appUrl?: string;
21
+ flow?: string | MiniAppFlowOptions;
22
+ params?: Record<string, string | number | boolean>;
23
+ buttonText?: string;
24
+ buttons?: any[];
25
+ footer?: string;
26
+ thumbnail?: Buffer | string;
27
+ useWebview?: boolean;
28
+ onThumbnailError?: (err: any) => void;
29
+ [key: string]: any;
30
+ }
31
+ export declare const buildMiniAppContent: (opts?: MiniAppOptions) => Promise<any>;
32
+ export declare const sendMiniApp: (sock: any, jid: any, miniApp: MiniAppOptions, options?: any) => Promise<any>;
33
+ export declare const createMiniAppLink: (baseUrl: string, params?: Record<string, string | number | boolean>, opts?: { secret?: string }) => string;
34
+ export declare const parseMiniAppParams: (link: string, opts?: { secret?: string }) => Record<string, string>;
35
+ export declare const buildFlowDataExchange: (action: string, data?: any, opts?: { version?: string; token?: string }) => any;
@@ -0,0 +1,213 @@
1
+ /**
2
+ * JAP@Add --- "Mini App" sender.
3
+ *
4
+ * Two delivery modes (both are real WhatsApp "mini app" patterns):
5
+ *
6
+ * 1. `url` — rich interactive card + CTA button opening your web app
7
+ * (in-app webview when supported, else the system browser). Optional
8
+ * `params` are appended as query string, so the app knows who opened it.
9
+ * 2. `flow` — WhatsApp Flows button (`flow_action`): a TRUE native in-chat
10
+ * mini app (forms/screens rendered inside WhatsApp, no browser at all).
11
+ * Requires a flow ID registered & published in Flows Manager. Both modes
12
+ * can be combined — the card then carries two buttons.
13
+ *
14
+ * ```js
15
+ * import { sendMiniApp } from '@japofc/baileys'
16
+ * await sendMiniApp(sock, jid, {
17
+ * title: 'My Mini App',
18
+ * body: 'Tap the button to open the app 👇',
19
+ * url: 'https://myapp.example.com',
20
+ * params: { ref: 'wa-bot' }, // → ?ref=wa-bot
21
+ * flow: { id: '123456789', cta: '📝 Isi Form', screen: 'WELCOME' }, // optional
22
+ * thumbnail: 'https://myapp.example.com/icon.png', // url or Buffer (optional)
23
+ * })
24
+ * ```
25
+ */
26
+ import { Boom } from '@hapi/boom';
27
+ import { createHmac, timingSafeEqual } from 'node:crypto';
28
+ export const MINI_APP_DEFAULT_BUTTON_TEXT = '🚀 Open App';
29
+ const MAX_THUMBNAIL_BYTES = 512 * 1024;
30
+ const resolveThumbnail = async (thumbnail) => {
31
+ if (!thumbnail) {
32
+ return undefined;
33
+ }
34
+ if (Buffer.isBuffer(thumbnail)) {
35
+ return thumbnail;
36
+ }
37
+ if (typeof thumbnail === 'string') {
38
+ let res;
39
+ try {
40
+ res = await fetch(thumbnail);
41
+ }
42
+ catch (err) {
43
+ throw new Boom(`miniApp.thumbnail: failed to fetch ${thumbnail} (${err?.message || err})`, { statusCode: 400 });
44
+ }
45
+ if (!res.ok) {
46
+ throw new Boom(`miniApp.thumbnail: fetch failed with HTTP ${res.status}`, { statusCode: 400 });
47
+ }
48
+ const buf = Buffer.from(await res.arrayBuffer());
49
+ if (!buf.length || buf.length > MAX_THUMBNAIL_BYTES) {
50
+ throw new Boom(`miniApp.thumbnail: must be 1–${MAX_THUMBNAIL_BYTES} bytes`, { statusCode: 400 });
51
+ }
52
+ return buf;
53
+ }
54
+ throw new Boom('miniApp.thumbnail must be a Buffer or a URL string', { statusCode: 400 });
55
+ };
56
+ const normalizeFlowConfig = (flow) => {
57
+ if (!flow) {
58
+ return undefined;
59
+ }
60
+ const cfg = typeof flow === 'string' ? { id: flow } : flow;
61
+ if (!cfg || typeof cfg !== 'object' || !cfg.id || typeof cfg.id !== 'string') {
62
+ throw new Boom('miniApp.flow.id is required (your published WhatsApp Flow ID)', { statusCode: 400 });
63
+ }
64
+ return cfg;
65
+ };
66
+ const appendUrlParams = (link, params) => {
67
+ if (!params || typeof params !== 'object' || !Object.keys(params).length) {
68
+ return link;
69
+ }
70
+ let u;
71
+ try {
72
+ u = new URL(link);
73
+ }
74
+ catch {
75
+ throw new Boom(`miniApp.url is not a valid URL: ${link}`, { statusCode: 400 });
76
+ }
77
+ for (const [k, v] of Object.entries(params)) {
78
+ u.searchParams.set(k, String(v));
79
+ }
80
+ return u.toString();
81
+ };
82
+ /**
83
+ * Build `sendMessage`-ready content for a Mini App card.
84
+ * Needs `url`, `flow`, or both. Thumbnail failures are non-fatal: the card is
85
+ * still built, just without the image.
86
+ */
87
+ export const buildMiniAppContent = async ({ title, body, text, url, appUrl, flow, params, buttonText, buttons = [], footer, thumbnail, useWebview = true, onThumbnailError, ...passthrough } = {}) => {
88
+ const link = url || appUrl;
89
+ const flowCfg = normalizeFlowConfig(flow);
90
+ if ((!link || typeof link !== 'string') && !flowCfg) {
91
+ throw new Boom('miniApp needs either `url` (webview app) or `flow` (WhatsApp Flow) — or both', { statusCode: 400 });
92
+ }
93
+ const mainText = body || text;
94
+ if (!mainText || typeof mainText !== 'string') {
95
+ throw new Boom('miniApp.body (or text) is required', { statusCode: 400 });
96
+ }
97
+ const finalUrl = link ? appendUrlParams(link, params) : undefined;
98
+ let thumb;
99
+ try {
100
+ thumb = await resolveThumbnail(thumbnail);
101
+ }
102
+ catch (err) {
103
+ if (typeof onThumbnailError === 'function') {
104
+ try {
105
+ onThumbnailError(err);
106
+ }
107
+ catch { }
108
+ }
109
+ }
110
+ const cardTitle = title || 'Mini App';
111
+ const nativeFlow = [
112
+ ...(finalUrl ? [{ buttonText: buttonText || MINI_APP_DEFAULT_BUTTON_TEXT, url: finalUrl, useWebview }] : []),
113
+ ...(flowCfg ? [{ buttonText: flowCfg.cta || '📝 Open', flow: flowCfg }] : []),
114
+ ...buttons
115
+ ];
116
+ const content = {
117
+ text: mainText,
118
+ footer: footer ?? cardTitle,
119
+ nativeFlow,
120
+ ...passthrough
121
+ };
122
+ // NOTE: only attach `thumbnail` when we actually have one — the ad-reply
123
+ // builder throws on a present-but-non-Buffer thumbnail value.
124
+ if (finalUrl) {
125
+ const externalAdReply = {
126
+ title: cardTitle,
127
+ body: mainText.slice(0, 120),
128
+ url: finalUrl,
129
+ mediaType: 1,
130
+ largeThumbnail: !!thumb
131
+ };
132
+ if (thumb) {
133
+ externalAdReply.thumbnail = thumb;
134
+ }
135
+ content.externalAdReply = content.externalAdReply || externalAdReply;
136
+ }
137
+ return content;
138
+ };
139
+ /**
140
+ * Standalone sender (same style as `sendButtons` / `sendInteractiveMessage`):
141
+ * `sendMiniApp(sock, jid, miniApp, options?)`. A `sock.sendMiniApp` alias exists too.
142
+ */
143
+ export const sendMiniApp = async (sock, jid, miniApp, options = {}) => {
144
+ if (!sock || typeof sock.sendMessage !== 'function') {
145
+ throw new Boom('sendMiniApp(sock, ...) requires an active Baileys socket', { statusCode: 400 });
146
+ }
147
+ return sock.sendMessage(jid, await buildMiniAppContent(miniApp), options);
148
+ };
149
+
150
+ /**
151
+ * JAP@Add --- build a mini-app deep link with optional HMAC-signed params, so
152
+ * your web app can verify the opener came from your bot untampered.
153
+ * `createMiniAppLink('https://app.example.com', { uid: '123' }, { secret })`
154
+ * → `'https://app.example.com/?uid=123&sig=…'`.
155
+ */
156
+ export const createMiniAppLink = (baseUrl, params = {}, { secret } = {}) => {
157
+ let u;
158
+ try {
159
+ u = new URL(baseUrl);
160
+ }
161
+ catch {
162
+ throw new Boom(`miniApp.url is not a valid URL: ${baseUrl}`, { statusCode: 400 });
163
+ }
164
+ for (const [k, v] of Object.entries(params || {})) {
165
+ u.searchParams.set(k, String(v));
166
+ }
167
+ if (secret) {
168
+ const payload = [...u.searchParams.entries()].sort(([a], [b]) => (a < b ? -1 : 1)).map(([k, v]) => `${k}=${v}`).join('&');
169
+ u.searchParams.set('sig', createHmac('sha256', secret).update(payload).digest('hex'));
170
+ }
171
+ return u.toString();
172
+ };
173
+
174
+ /**
175
+ * JAP@Add --- parse + (optionally) verify a mini-app link's params.
176
+ * Throws when `secret` is given and the signature is missing/invalid.
177
+ */
178
+ export const parseMiniAppParams = (link, { secret } = {}) => {
179
+ let u;
180
+ try {
181
+ u = new URL(link);
182
+ }
183
+ catch {
184
+ throw new Boom(`miniApp.url is not a valid URL: ${link}`, { statusCode: 400 });
185
+ }
186
+ const out = {};
187
+ for (const [k, v] of u.searchParams.entries()) {
188
+ if (k !== 'sig') {
189
+ out[k] = v;
190
+ }
191
+ }
192
+ if (secret) {
193
+ const sig = u.searchParams.get('sig') || '';
194
+ const payload = Object.entries(out).sort(([a], [b]) => (a < b ? -1 : 1)).map(([k, v]) => `${k}=${v}`).join('&');
195
+ const expect = createHmac('sha256', secret).update(payload).digest('hex');
196
+ const ok = sig.length === expect.length && (() => { try { return timingSafeEqual(Buffer.from(sig), Buffer.from(expect)); } catch { return false; } })();
197
+ if (!ok) {
198
+ throw new Boom('miniApp.params: invalid signature', { statusCode: 403 });
199
+ }
200
+ }
201
+ return out;
202
+ };
203
+
204
+ /**
205
+ * JAP@Add --- build a WhatsApp Flows `data_exchange` action payload
206
+ * (`{ version, action, data, token? }`) for the `flow.actionPayload` shortcut.
207
+ */
208
+ export const buildFlowDataExchange = (action, data = {}, { version = '3.0', token } = {}) => {
209
+ if (!action || typeof action !== 'string') {
210
+ throw new Boom('flow action is required (e.g. navigate, data_exchange)', { statusCode: 400 });
211
+ }
212
+ return { version, action, data, ...(token ? { token } : {}) };
213
+ };
@@ -0,0 +1,20 @@
1
+ export function makeNoiseHandler({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }: {
2
+ keyPair: {
3
+ private: any;
4
+ public: any;
5
+ };
6
+ NOISE_HEADER: any;
7
+ logger: any;
8
+ routingInfo: any;
9
+ }): {
10
+ encrypt: (plaintext: any) => any;
11
+ decrypt: (ciphertext: any) => any;
12
+ authenticate: (data: any) => void;
13
+ mixIntoKey: (data: any) => void;
14
+ finishInit: () => Promise<void>;
15
+ processHandshake: ({ serverHello }: {
16
+ serverHello: any;
17
+ }, noiseKey: any) => any;
18
+ encodeFrame: (data: any) => any;
19
+ decodeFrame: (newData: any, onFrame: any) => Promise<void>;
20
+ };
@@ -0,0 +1,200 @@
1
+ import { Boom } from '@hapi/boom';
2
+ import { proto } from '../../WAProto/index.js';
3
+ import { NOISE_MODE, WA_CERT_DETAILS } from '../Defaults/index.js';
4
+ import { decodeBinaryNode } from '../WABinary/index.js';
5
+ import { aesDecryptGCM, aesEncryptGCM, Curve, hkdf, sha256 } from './crypto.js';
6
+ const IV_LENGTH = 12;
7
+ const EMPTY_BUFFER = Buffer.alloc(0);
8
+ const generateIV = (counter) => {
9
+ const iv = new ArrayBuffer(IV_LENGTH);
10
+ new DataView(iv).setUint32(8, counter);
11
+ return new Uint8Array(iv);
12
+ };
13
+ class TransportState {
14
+ constructor(encKey, decKey) {
15
+ this.encKey = encKey;
16
+ this.decKey = decKey;
17
+ this.readCounter = 0;
18
+ this.writeCounter = 0;
19
+ this.iv = new Uint8Array(IV_LENGTH);
20
+ }
21
+ encrypt(plaintext) {
22
+ const c = this.writeCounter++;
23
+ this.iv[8] = (c >>> 24) & 0xff;
24
+ this.iv[9] = (c >>> 16) & 0xff;
25
+ this.iv[10] = (c >>> 8) & 0xff;
26
+ this.iv[11] = c & 0xff;
27
+ return aesEncryptGCM(plaintext, this.encKey, this.iv, EMPTY_BUFFER);
28
+ }
29
+ decrypt(ciphertext) {
30
+ const c = this.readCounter++;
31
+ this.iv[8] = (c >>> 24) & 0xff;
32
+ this.iv[9] = (c >>> 16) & 0xff;
33
+ this.iv[10] = (c >>> 8) & 0xff;
34
+ this.iv[11] = c & 0xff;
35
+ return aesDecryptGCM(ciphertext, this.decKey, this.iv, EMPTY_BUFFER);
36
+ }
37
+ }
38
+ export const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }) => {
39
+ logger = logger.child({ class: 'ns' });
40
+ const data = Buffer.from(NOISE_MODE);
41
+ let hash = data.byteLength === 32 ? data : sha256(data);
42
+ let salt = hash;
43
+ let encKey = hash;
44
+ let decKey = hash;
45
+ let counter = 0;
46
+ let sentIntro = false;
47
+ let inBytes = Buffer.alloc(0);
48
+ let transport = null;
49
+ let isWaitingForTransport = false;
50
+ let pendingOnFrame = null;
51
+ let introHeader;
52
+ if (routingInfo) {
53
+ introHeader = Buffer.alloc(7 + routingInfo.byteLength + NOISE_HEADER.length);
54
+ introHeader.write('ED', 0, 'utf8');
55
+ introHeader.writeUint8(0, 2);
56
+ introHeader.writeUint8(1, 3);
57
+ introHeader.writeUint8(routingInfo.byteLength >> 16, 4);
58
+ introHeader.writeUint16BE(routingInfo.byteLength & 65535, 5);
59
+ introHeader.set(routingInfo, 7);
60
+ introHeader.set(NOISE_HEADER, 7 + routingInfo.byteLength);
61
+ }
62
+ else {
63
+ introHeader = Buffer.from(NOISE_HEADER);
64
+ }
65
+ const authenticate = (data) => {
66
+ if (!transport) {
67
+ hash = sha256(Buffer.concat([hash, data]));
68
+ }
69
+ };
70
+ const encrypt = (plaintext) => {
71
+ if (transport) {
72
+ return transport.encrypt(plaintext);
73
+ }
74
+ const result = aesEncryptGCM(plaintext, encKey, generateIV(counter++), hash);
75
+ authenticate(result);
76
+ return result;
77
+ };
78
+ const decrypt = (ciphertext) => {
79
+ if (transport) {
80
+ return transport.decrypt(ciphertext);
81
+ }
82
+ const result = aesDecryptGCM(ciphertext, decKey, generateIV(counter++), hash);
83
+ authenticate(ciphertext);
84
+ return result;
85
+ };
86
+ const localHKDF = (data) => {
87
+ const key = hkdf(Buffer.from(data), 64, { salt, info: '' });
88
+ return [key.subarray(0, 32), key.subarray(32)];
89
+ };
90
+ const mixIntoKey = (data) => {
91
+ const [write, read] = localHKDF(data);
92
+ salt = write;
93
+ encKey = read;
94
+ decKey = read;
95
+ counter = 0;
96
+ };
97
+ const finishInit = async () => {
98
+ isWaitingForTransport = true;
99
+ const [write, read] = localHKDF(new Uint8Array(0));
100
+ transport = new TransportState(write, read);
101
+ isWaitingForTransport = false;
102
+ logger.trace('Noise handler transitioned to Transport state');
103
+ if (pendingOnFrame) {
104
+ logger.trace({ length: inBytes.length }, 'Flushing buffered frames after transport ready');
105
+ await processData(pendingOnFrame);
106
+ pendingOnFrame = null;
107
+ }
108
+ };
109
+ const processData = async (onFrame) => {
110
+ let size;
111
+ while (true) {
112
+ if (inBytes.length < 3)
113
+ return;
114
+ size = (inBytes[0] << 16) | (inBytes[1] << 8) | inBytes[2];
115
+ if (inBytes.length < size + 3)
116
+ return;
117
+ let frame = inBytes.subarray(3, size + 3);
118
+ inBytes = inBytes.subarray(size + 3);
119
+ if (transport) {
120
+ const result = transport.decrypt(frame);
121
+ frame = await decodeBinaryNode(result);
122
+ }
123
+ if (logger.level === 'trace') {
124
+ logger.trace({ msg: frame?.attrs?.id }, 'recv frame');
125
+ }
126
+ onFrame(frame);
127
+ }
128
+ };
129
+ authenticate(NOISE_HEADER);
130
+ authenticate(publicKey);
131
+ return {
132
+ encrypt,
133
+ decrypt,
134
+ authenticate,
135
+ mixIntoKey,
136
+ finishInit,
137
+ processHandshake: ({ serverHello }, noiseKey) => {
138
+ authenticate(serverHello.ephemeral);
139
+ mixIntoKey(Curve.sharedKey(privateKey, serverHello.ephemeral));
140
+ const decStaticContent = decrypt(serverHello.static);
141
+ mixIntoKey(Curve.sharedKey(privateKey, decStaticContent));
142
+ const certDecoded = decrypt(serverHello.payload);
143
+ const { intermediate: certIntermediate, leaf } = proto.CertChain.decode(certDecoded);
144
+ // leaf
145
+ if (!leaf?.details || !leaf?.signature) {
146
+ throw new Boom('invalid noise leaf certificate', { statusCode: 400 });
147
+ }
148
+ if (!certIntermediate?.details || !certIntermediate?.signature) {
149
+ throw new Boom('invalid noise intermediate certificate', { statusCode: 400 });
150
+ }
151
+ const details = proto.CertChain.NoiseCertificate.Details.decode(certIntermediate.details);
152
+ const { issuerSerial } = details;
153
+ const verify = Curve.verify(details.key, leaf.details, leaf.signature);
154
+ const verifyIntermediate = Curve.verify(WA_CERT_DETAILS.PUBLIC_KEY, certIntermediate.details, certIntermediate.signature);
155
+ if (!verify) {
156
+ throw new Boom('noise certificate signature invalid', { statusCode: 400 });
157
+ }
158
+ if (!verifyIntermediate) {
159
+ throw new Boom('noise intermediate certificate signature invalid', { statusCode: 400 });
160
+ }
161
+ if (issuerSerial !== WA_CERT_DETAILS.SERIAL) {
162
+ throw new Boom('certification match failed', { statusCode: 400 });
163
+ }
164
+ const keyEnc = encrypt(noiseKey.public);
165
+ mixIntoKey(Curve.sharedKey(noiseKey.private, serverHello.ephemeral));
166
+ return keyEnc;
167
+ },
168
+ encodeFrame: (data) => {
169
+ if (transport) {
170
+ data = transport.encrypt(data);
171
+ }
172
+ const dataLen = data.byteLength;
173
+ const introSize = sentIntro ? 0 : introHeader.length;
174
+ const frame = Buffer.allocUnsafe(introSize + 3 + dataLen);
175
+ if (!sentIntro) {
176
+ frame.set(introHeader);
177
+ sentIntro = true;
178
+ }
179
+ frame[introSize] = (dataLen >>> 16) & 0xff;
180
+ frame[introSize + 1] = (dataLen >>> 8) & 0xff;
181
+ frame[introSize + 2] = dataLen & 0xff;
182
+ frame.set(data, introSize + 3);
183
+ return frame;
184
+ },
185
+ decodeFrame: async (newData, onFrame) => {
186
+ if (isWaitingForTransport) {
187
+ inBytes = Buffer.concat([inBytes, newData]);
188
+ pendingOnFrame = onFrame;
189
+ return;
190
+ }
191
+ if (inBytes.length === 0) {
192
+ inBytes = Buffer.from(newData);
193
+ }
194
+ else {
195
+ inBytes = Buffer.concat([inBytes, newData]);
196
+ }
197
+ await processData(onFrame);
198
+ }
199
+ };
200
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Creates a processor for offline stanza nodes that:
3
+ * - Queues nodes for sequential processing
4
+ * - Yields to the event loop periodically to avoid blocking
5
+ * - Catches handler errors to prevent the processing loop from crashing
6
+ */
7
+ export function makeOfflineNodeProcessor(nodeProcessorMap: any, deps: any, batchSize?: number): {
8
+ enqueue: (type: any, node: any) => void;
9
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Creates a processor for offline stanza nodes that:
3
+ * - Queues nodes for sequential processing
4
+ * - Yields to the event loop periodically to avoid blocking
5
+ * - Catches handler errors to prevent the processing loop from crashing
6
+ */
7
+ export function makeOfflineNodeProcessor(nodeProcessorMap, deps, batchSize = 10) {
8
+ const nodes = [];
9
+ let isProcessing = false;
10
+ const enqueue = (type, node) => {
11
+ nodes.push({ type, node });
12
+ if (isProcessing) {
13
+ return;
14
+ }
15
+ isProcessing = true;
16
+ const promise = async () => {
17
+ let processedInBatch = 0;
18
+ while (nodes.length && deps.isWsOpen()) {
19
+ const { type, node } = nodes.shift();
20
+ const nodeProcessor = nodeProcessorMap.get(type);
21
+ if (!nodeProcessor) {
22
+ deps.onUnexpectedError(new Error(`unknown offline node type: ${type}`), 'processing offline node');
23
+ continue;
24
+ }
25
+ await nodeProcessor(node).catch(err => deps.onUnexpectedError(err, `processing offline ${type}`));
26
+ processedInBatch++;
27
+ // Yield to event loop after processing a batch
28
+ // This prevents blocking the event loop for too long when there are many offline nodes
29
+ if (processedInBatch >= batchSize) {
30
+ processedInBatch = 0;
31
+ await deps.yieldToEventLoop();
32
+ }
33
+ }
34
+ isProcessing = false;
35
+ };
36
+ promise().catch(error => deps.onUnexpectedError(error, 'processing offline nodes'));
37
+ };
38
+ return { enqueue };
39
+ }
@@ -0,0 +1,14 @@
1
+ import type { proto } from '../../WAProto/index.js';
2
+ export interface ProcessedPastParticipant {
3
+ jid: string;
4
+ leaveTs?: number;
5
+ leaveReason?: 'left' | 'removed';
6
+ }
7
+ export interface ProcessedPastParticipants {
8
+ groupJid: string;
9
+ participants: ProcessedPastParticipant[];
10
+ }
11
+ /** Process proto.IPastParticipants[] from a history sync payload into a structured list per group. */
12
+ export declare const processPastParticipants: (pastParticipantsList: any[]) => ProcessedPastParticipants[];
13
+ /** Check if a history sync event contains past participants data. */
14
+ export declare const hasPastParticipants: (event: { pastParticipants?: unknown[] }) => boolean;
@@ -0,0 +1,40 @@
1
+ // JAP@Utils --- past-participants helpers (left/kicked member history).
2
+ // No logic changes — @japofc/baileys's own WAProto already has the
3
+ // `proto.PastParticipant.LeaveReason` enum and `HistorySync.pastParticipants`
4
+ // field this depends on (confirmed present), so this ports as-is.
5
+ //
6
+ // This reads WhatsApp's own server-provided participant-leave history from
7
+ // a history-sync payload (`proto.IPastParticipants[]`) — it's real protocol
8
+ // data, not something reconstructed by listening to live events, so it
9
+ // includes participants who left/were removed *before* this session ever
10
+ // connected (which a live `group-participants.update` listener can never
11
+ // see).
12
+ import { proto } from '../../WAProto/index.js';
13
+
14
+ /**
15
+ * Process proto.IPastParticipants[] from a history sync payload.
16
+ * Returns a structured list per group.
17
+ */
18
+ export const processPastParticipants = (pastParticipantsList) => {
19
+ return pastParticipantsList.map((pp) => {
20
+ const groupJid = pp.groupJid ?? '';
21
+ const participants = (pp.pastParticipants ?? []).map((p) => ({
22
+ jid: p.userJid ?? '',
23
+ leaveTs: p.leaveTs ? Number(p.leaveTs) : undefined,
24
+ leaveReason: p.leaveReason === proto.PastParticipant.LeaveReason.LEFT
25
+ ? 'left'
26
+ : p.leaveReason === proto.PastParticipant.LeaveReason.REMOVED
27
+ ? 'removed'
28
+ : undefined
29
+ }));
30
+ return { groupJid, participants };
31
+ });
32
+ };
33
+
34
+ /**
35
+ * Check if a history sync event contains past participants data.
36
+ * (pastParticipants field replaces chunkOrder in this patch)
37
+ */
38
+ export const hasPastParticipants = (event) => {
39
+ return Array.isArray(event.pastParticipants) && event.pastParticipants.length > 0;
40
+ };