@vanzxy/baileys 1.6.2 β†’ 1.6.4

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.

Potentially problematic release.


This version of @vanzxy/baileys might be problematic. Click here for more details.

Files changed (51) hide show
  1. package/NOTICE.md +50 -0
  2. package/lib/Utils/A2UI.js +217 -0
  3. package/lib/Utils/MessageBuilder.js +332 -46
  4. package/lib/Utils/MessageBuilder_d.ts +45 -0
  5. package/lib/Utils/PersistentStore.js +592 -0
  6. package/lib/Utils/PersistentStore_d.ts +60 -0
  7. package/lib/Utils/anti-delete.d.ts +68 -0
  8. package/lib/Utils/anti-delete.js +185 -0
  9. package/lib/Utils/auto-reply.d.ts +47 -0
  10. package/lib/Utils/auto-reply.js +155 -0
  11. package/lib/Utils/button-helper-utils.js +314 -0
  12. package/lib/Utils/button-sender.js +817 -0
  13. package/lib/Utils/chat-history-helpers.d.ts +21 -0
  14. package/lib/Utils/chat-history-helpers.js +71 -0
  15. package/lib/Utils/index.d.ts +11 -0
  16. package/lib/Utils/index.js +16 -0
  17. package/lib/Utils/media-messages.d.ts +18 -0
  18. package/lib/Utils/media-messages.js +71 -0
  19. package/lib/Utils/media-set.d.ts +13 -0
  20. package/lib/Utils/media-set.js +165 -0
  21. package/lib/Utils/message-kind.js +139 -0
  22. package/lib/Utils/message-search.d.ts +44 -0
  23. package/lib/Utils/message-search.js +174 -0
  24. package/lib/Utils/scheduling.d.ts +42 -0
  25. package/lib/Utils/scheduling.js +140 -0
  26. package/lib/Utils/status.d.ts +50 -0
  27. package/lib/Utils/status.js +108 -0
  28. package/lib/Utils/stickerpack.d.ts +51 -0
  29. package/lib/Utils/stickerpack.js +276 -0
  30. package/lib/Utils/templates.d.ts +76 -0
  31. package/lib/Utils/templates.js +151 -0
  32. package/lib/Utils/use-sqlite-auth-state.js +28 -1
  33. package/lib/Utils/vcard.d.ts +58 -0
  34. package/lib/Utils/vcard.js +94 -0
  35. package/lib/VoIP/audio-feeder.d.ts +15 -0
  36. package/lib/VoIP/audio-feeder.js +132 -0
  37. package/lib/VoIP/index.js +277 -0
  38. package/lib/VoIP/relay-transport.d.ts +43 -0
  39. package/lib/VoIP/relay-transport.js +559 -0
  40. package/lib/VoIP/signaling.js +624 -0
  41. package/lib/VoIP/types.d.ts +69 -0
  42. package/lib/VoIP/types.js +17 -0
  43. package/lib/VoIP/wasm-engine.d.ts +103 -0
  44. package/lib/VoIP/wasm-engine.js +1214 -0
  45. package/lib/VoIP/worker-bootstrap.js +1042 -0
  46. package/lib/WABinary/generic-utils.js +8 -0
  47. package/lib/assets/wasm/loader.js +5 -0
  48. package/lib/assets/wasm/whatsapp.wasm +0 -0
  49. package/lib/assets/wasm/worker-modules.js +273 -0
  50. package/lib/index.js +4 -0
  51. package/package.json +22 -1
@@ -0,0 +1,314 @@
1
+ // Evernight AI β€” lib/Utils/button-helper-utils.js / Creator : VanzxyπŸƒ
2
+ // Ported from @queenanya/baileys (Bail-master fork) src/addons/message-utils.ts
3
+ // Original credit inside that file: "Ported from @ryuu-reinzz/button-helper v2.2.5"
4
+ // Converted TS -> JS ESM to match @vanzxy/baileys compiled-lib conventions.
5
+
6
+ import { randomBytes } from 'crypto';
7
+ import { generateWAMessage, generateWAMessageFromContent, normalizeMessageContent } from './messages.js';
8
+ import { getUrlFromDirectPath } from './messages-media.js';
9
+ import { unixTimestampSeconds } from './generics.js';
10
+ import { getBinaryNodeChild, isJidGroup, isJidNewsletter, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
11
+ import { QueryIds, XWAPaths } from '../Types/Mex.js';
12
+
13
+ // ─────────────────────────────────────────────────────────────────────────────
14
+ // SECTION 1 β€” Message Type Detection
15
+ // ─────────────────────────────────────────────────────────────────────────────
16
+
17
+ /** @param {import('../../WAProto/index.js').proto.IMessage} message */
18
+ export function getMediaType(message) {
19
+ if (message.imageMessage) return 'image';
20
+ if (message.videoMessage) return message.videoMessage.gifPlayback ? 'gif' : 'video';
21
+ if (message.audioMessage) return message.audioMessage.ptt ? 'ptt' : 'audio';
22
+ if (message.contactMessage) return 'vcard';
23
+ if (message.documentMessage) return 'document';
24
+ if (message.contactsArrayMessage) return 'contact_array';
25
+ if (message.liveLocationMessage) return 'livelocation';
26
+ if (message.stickerMessage) return 'sticker';
27
+ if (message.listMessage) return 'list';
28
+ if (message.listResponseMessage) return 'list_response';
29
+ if (message.buttonsResponseMessage) return 'buttons_response';
30
+ if (message.orderMessage) return 'order';
31
+ if (message.productMessage) return 'product';
32
+ if (message.interactiveResponseMessage) return 'native_flow_response';
33
+ if (message.groupInviteMessage) return 'url';
34
+ return '';
35
+ }
36
+
37
+ /** @param {import('../../WAProto/index.js').proto.IMessage} message */
38
+ export function getMessageType(message) {
39
+ const normalizedMessage = normalizeMessageContent(message);
40
+ if (!normalizedMessage) return 'text';
41
+ if (normalizedMessage.reactionMessage || normalizedMessage.encReactionMessage) return 'reaction';
42
+ if (
43
+ normalizedMessage.pollCreationMessage ||
44
+ normalizedMessage.pollCreationMessageV2 ||
45
+ normalizedMessage.pollCreationMessageV3 ||
46
+ normalizedMessage.pollUpdateMessage
47
+ )
48
+ return 'poll';
49
+ if (normalizedMessage.eventMessage) return 'event';
50
+ if (getMediaType(normalizedMessage) !== '') return 'media';
51
+ return 'text';
52
+ }
53
+
54
+ // ─────────────────────────────────────────────────────────────────────────────
55
+ // SECTION 2 β€” Button / Biz Node Helpers
56
+ // ─────────────────────────────────────────────────────────────────────────────
57
+
58
+ /** @param {import('../../WAProto/index.js').proto.IMessage} message */
59
+ export function getButtonType(message) {
60
+ const inner = message.viewOnceMessageV2Extension?.message || message;
61
+ if (inner.listMessage) return 'list';
62
+ if (inner.buttonsMessage) return 'buttons';
63
+ if (inner.interactiveMessage?.nativeFlowMessage) return 'native_flow';
64
+ if (inner.interactiveMessage?.carouselMessage) return 'native_flow';
65
+ if (message.viewOnceMessage?.message?.interactiveMessage?.carouselMessage) return 'native_flow';
66
+ if (message.viewOnceMessageV2?.message?.interactiveMessage?.carouselMessage) return 'native_flow';
67
+ if (message.viewOnceMessage?.message?.interactiveMessage?.nativeFlowMessage) return 'native_flow';
68
+ if (message.viewOnceMessageV2?.message?.interactiveMessage?.nativeFlowMessage) return 'native_flow';
69
+ if (message.viewOnceMessageV2Extension?.message?.interactiveMessage?.nativeFlowMessage) return 'native_flow';
70
+ if (message.viewOnceMessageV2Extension?.message?.interactiveMessage?.carouselMessage) return 'native_flow';
71
+ return undefined;
72
+ }
73
+
74
+ /**
75
+ * Derive the binary node(s) that must accompany a button/interactive/list
76
+ * message so it renders correctly across WA Messenger + WA Business,
77
+ * Android + iOS.
78
+ * @param {import('../../WAProto/index.js').proto.IMessage} message
79
+ * @returns {import('../WABinary/index.js').BinaryNode}
80
+ */
81
+ export function getButtonArgs(message) {
82
+ const inner = message.viewOnceMessageV2Extension?.message || message;
83
+ const nativeFlow =
84
+ inner.interactiveMessage?.nativeFlowMessage ||
85
+ message.viewOnceMessage?.message?.interactiveMessage?.nativeFlowMessage ||
86
+ message.viewOnceMessageV2?.message?.interactiveMessage?.nativeFlowMessage;
87
+ const carouselMessage =
88
+ inner.interactiveMessage?.carouselMessage ||
89
+ message.viewOnceMessage?.message?.interactiveMessage?.carouselMessage ||
90
+ message.viewOnceMessageV2?.message?.interactiveMessage?.carouselMessage;
91
+
92
+ const firstButtonName =
93
+ nativeFlow?.buttons?.[0]?.name ||
94
+ carouselMessage?.cards?.[0]?.nativeFlowMessage?.buttons?.[0]?.name;
95
+ const nativeFlowSpecials = [
96
+ 'mpm',
97
+ 'cta_catalog',
98
+ 'send_location',
99
+ 'call_permission_request',
100
+ 'wa_payment_transaction_details',
101
+ 'automated_greeting_message_view_catalog'
102
+ ];
103
+ const ts = unixTimestampSeconds().toString();
104
+ if (nativeFlow && (firstButtonName === 'review_and_pay' || firstButtonName === 'payment_info')) {
105
+ return {
106
+ tag: 'biz',
107
+ attrs: { native_flow_name: firstButtonName === 'review_and_pay' ? 'order_details' : firstButtonName }
108
+ };
109
+ }
110
+
111
+ if (nativeFlow && nativeFlowSpecials.includes(firstButtonName ?? '')) {
112
+ return {
113
+ tag: 'biz',
114
+ attrs: { actual_actors: '2', host_storage: '2', privacy_mode_ts: ts },
115
+ content: [
116
+ {
117
+ tag: 'interactive',
118
+ attrs: { type: 'native_flow', v: '1' },
119
+ content: [{ tag: 'native_flow', attrs: { v: '2', name: firstButtonName } }]
120
+ },
121
+ { tag: 'quality_control', attrs: { source_type: 'third_party' } }
122
+ ]
123
+ };
124
+ }
125
+
126
+ if (nativeFlow || carouselMessage || message.buttonsMessage) {
127
+ return {
128
+ tag: 'biz',
129
+ attrs: {},
130
+ content: [
131
+ {
132
+ tag: 'interactive',
133
+ attrs: { type: 'native_flow', v: '1' },
134
+ content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }]
135
+ }
136
+ ]
137
+ };
138
+ }
139
+
140
+ if (inner.listMessage) {
141
+ return { tag: 'biz', attrs: {}, content: [{ tag: 'list', attrs: { v: '2', type: 'product_list' } }] };
142
+ }
143
+
144
+ return { tag: 'biz', attrs: {} };
145
+ }
146
+
147
+ // ─────────────────────────────────────────────────────────────────────────────
148
+ // SECTION 3 β€” WS Extras (mentions, media, MD patch, album, socket extras)
149
+ // ─────────────────────────────────────────────────────────────────────────────
150
+
151
+ /** Build contextInfo for @mention or @all. */
152
+ export const buildMentionContextInfo = (message) => {
153
+ if (message.mentionAll) return { contextInfo: { nonJidMentions: 1 } };
154
+ if (message.mentions?.length) return { contextInfo: { mentionedJid: message.mentions } };
155
+ return { contextInfo: {} };
156
+ };
157
+
158
+ /** Extract embedded media from buttons/interactive message (top-level or header-nested). */
159
+ export const extractFromButtonsMessage = (msg) => {
160
+ const header = typeof msg.header === 'object' && msg.header !== null;
161
+ if (header ? msg.header?.imageMessage : msg.imageMessage)
162
+ return { imageMessage: header ? msg.header.imageMessage : msg.imageMessage };
163
+ if (header ? msg.header?.videoMessage : msg.videoMessage)
164
+ return { videoMessage: header ? msg.header.videoMessage : msg.videoMessage };
165
+ if (header ? msg.header?.documentMessage : msg.documentMessage)
166
+ return { documentMessage: header ? msg.header.documentMessage : msg.documentMessage };
167
+ return null;
168
+ };
169
+
170
+ /** Normalise media input: string β†’ { url }, Buffer β†’ as-is, others β†’ as-is. */
171
+ export const normalizeMediaInput = (media) => {
172
+ if (!media) return media;
173
+ if (Buffer.isBuffer(media)) return media;
174
+ if (typeof media === 'string') return { url: media };
175
+ return media;
176
+ };
177
+
178
+ /** Wrap buttons/template/list/interactive in viewOnceMessageV2Extension for MD clients. */
179
+ export const patchMessageForMdIfRequired = (message) => {
180
+ if (
181
+ message?.buttonsMessage ||
182
+ message?.templateMessage ||
183
+ message?.listMessage ||
184
+ message?.interactiveMessage?.nativeFlowMessage
185
+ ) {
186
+ return {
187
+ viewOnceMessageV2Extension: {
188
+ message: {
189
+ messageContextInfo: { deviceListMetadataVersion: 2, deviceListMetadata: {} },
190
+ ...message
191
+ }
192
+ }
193
+ };
194
+ }
195
+
196
+ return message;
197
+ };
198
+
199
+ /**
200
+ * Build and relay an album (multi-image/video) message.
201
+ * @param {string} jid
202
+ * @param {Array<object>} albums
203
+ * @param {{ userJid: string, suki: { relayMessage: Function, waUploadToServer: Function } }} options
204
+ * @returns {Promise<Array<object>>} Array of individual media WAMessage objects
205
+ * @example
206
+ * const items = await prepareAlbumMessageContent(jid, [
207
+ * { image: { url: 'https://...' }, caption: 'Photo 1' },
208
+ * { video: { url: 'https://...' }, caption: 'Video 1' }
209
+ * ], { userJid: sock.user.id, suki: sock })
210
+ */
211
+ export const prepareAlbumMessageContent = async (jid, albums, options) => {
212
+ const messages = [];
213
+
214
+ const albumMsg = generateWAMessageFromContent(
215
+ jid,
216
+ {
217
+ albumMessage: {
218
+ expectedImageCount: albums.filter((item) => 'image' in item).length,
219
+ expectedVideoCount: albums.filter((item) => 'video' in item).length
220
+ }
221
+ },
222
+ { userJid: options.userJid }
223
+ );
224
+
225
+ await options.suki.relayMessage(jid, albumMsg.message, { messageId: albumMsg.key.id });
226
+
227
+ for (const media of albums) {
228
+ let mediaMsg;
229
+ const uploadFn = async (encFilePath, opts) => {
230
+ const res = await options.suki.waUploadToServer(encFilePath, {
231
+ ...opts,
232
+ newsletter: isJidNewsletter(jid)
233
+ });
234
+ return {
235
+ mediaUrl: res.url ?? '',
236
+ directPath: res.directPath ?? '',
237
+ handle: res.handle,
238
+ mediaKey: res.mediaKey,
239
+ fileEncSha256: res.fileEncSha256,
240
+ fileSha256: res.fileSha256,
241
+ fileLength: res.fileLength
242
+ };
243
+ };
244
+
245
+ const sharedOpts = { userJid: options.userJid, upload: uploadFn };
246
+
247
+ if ('image' in media && media.image) mediaMsg = await generateWAMessage(jid, media, sharedOpts);
248
+ else if ('video' in media && media.video) mediaMsg = await generateWAMessage(jid, media, sharedOpts);
249
+
250
+ if (mediaMsg) {
251
+ mediaMsg.message.messageContextInfo = {
252
+ messageSecret: randomBytes(32),
253
+ messageAssociation: { associationType: 1, parentMessageKey: albumMsg.key }
254
+ };
255
+ messages.push(mediaMsg);
256
+ }
257
+ }
258
+
259
+ return messages;
260
+ };
261
+
262
+ /**
263
+ * Addon factory for socket-level message extras (profilePictureUrl, getEphemeralGroup).
264
+ * @param {{ query: Function, newsletterWMexQuery?: Function }} ctx
265
+ */
266
+ export const makeMessageExtrasAddon = (ctx) => {
267
+ const { query, newsletterWMexQuery } = ctx;
268
+
269
+ /**
270
+ * Fetch profile picture URL for any JID, including newsletters.
271
+ * @example
272
+ * const url = await sock.profilePictureUrl('1234567890@s.whatsapp.net')
273
+ */
274
+ const profilePictureUrl = async (jid) => {
275
+ if (isJidNewsletter(jid) && newsletterWMexQuery) {
276
+ const node = await newsletterWMexQuery(undefined, QueryIds.METADATA, {
277
+ input: { key: jid, type: 'JID', view_role: 'GUEST' },
278
+ fetch_viewer_metadata: true,
279
+ fetch_full_image: true,
280
+ fetch_creation_time: true
281
+ });
282
+ const resultStr = getBinaryNodeChild(node, 'result')?.content?.toString();
283
+ if (!resultStr) return null;
284
+
285
+ const metadata = JSON.parse(resultStr).data[XWAPaths.xwa2_newsletter_metadata];
286
+ return getUrlFromDirectPath(metadata?.thread_metadata?.picture?.direct_path || '');
287
+ }
288
+
289
+ const result = await query({
290
+ tag: 'iq',
291
+ attrs: { target: jidNormalizedUser(jid), to: S_WHATSAPP_NET, type: 'get', xmlns: 'w:profile:picture' },
292
+ content: [{ tag: 'picture', attrs: { type: 'image', query: 'url' }, content: undefined }]
293
+ });
294
+ return getBinaryNodeChild(result, 'picture')?.attrs?.url || null;
295
+ };
296
+
297
+ /**
298
+ * Query the ephemeral (disappearing messages) timer for a group.
299
+ * @returns {Promise<number|string>} timer in seconds, or 0 if not set
300
+ * @example
301
+ * const timer = await sock.getEphemeralGroup('120363xxx@g.us')
302
+ */
303
+ const getEphemeralGroup = async (jid) => {
304
+ if (!isJidGroup(jid)) throw new TypeError('Jid should originate from a group!');
305
+ const result = await query({
306
+ tag: 'iq',
307
+ attrs: { id: `ephemeral-${Date.now()}`, to: jid, type: 'get', xmlns: 'w:g2' },
308
+ content: [{ tag: 'query', attrs: { request: 'interactive' }, content: undefined }]
309
+ });
310
+ return getBinaryNodeChild(getBinaryNodeChild(result, 'group'), 'ephemeral')?.attrs?.expiration || 0;
311
+ };
312
+
313
+ return { profilePictureUrl, getEphemeralGroup };
314
+ };