@alannxd/baileys 6.2.7 → 6.2.8

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 (45) hide show
  1. package/README.md +440 -203
  2. package/lib/Defaults/index.js +2 -2
  3. package/lib/Socket/Client/websocket.js +35 -5
  4. package/lib/Socket/chats.js +0 -5
  5. package/lib/Socket/index.js +1 -9
  6. package/lib/Socket/luxu.js +4 -5
  7. package/lib/Socket/messages-recv.js +1 -1
  8. package/lib/Socket/messages-send.js +56 -114
  9. package/lib/Socket/mex.js +38 -51
  10. package/lib/Socket/newsletter.js +276 -745
  11. package/lib/Socket/socket.js +27 -161
  12. package/lib/Socket/username.js +204 -206
  13. package/lib/Store/make-in-memory-store.js +1 -47
  14. package/lib/Types/Mex.js +2 -76
  15. package/lib/Utils/browser-utils.js +1 -0
  16. package/lib/Utils/generics.js +2 -2
  17. package/lib/Utils/index.js +0 -1
  18. package/lib/Utils/messages-media.js +0 -82
  19. package/lib/Utils/messages.js +2 -136
  20. package/lib/WAUSync/Protocols/USyncContactProtocol.js +50 -52
  21. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +52 -55
  22. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +25 -28
  23. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -37
  24. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +23 -25
  25. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +51 -0
  26. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +29 -0
  27. package/lib/WAUSync/Protocols/index.js +6 -12
  28. package/lib/WAUSync/USyncQuery.js +96 -149
  29. package/lib/WAUSync/USyncUser.js +29 -54
  30. package/lib/WAUSync/index.js +4 -3
  31. package/lib/index.js +5 -2
  32. package/package.json +14 -13
  33. package/lib/Socket/graphql.js +0 -716
  34. package/lib/Socket/interop.js +0 -463
  35. package/lib/Socket/message-builder.js +0 -475
  36. package/lib/Socket/privacy.js +0 -318
  37. package/lib/Utils/sticker.js +0 -133
  38. package/lib/Utils/use-sqlite-auth-state.js +0 -162
  39. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +0 -53
  40. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +0 -43
  41. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +0 -58
  42. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -30
  43. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +0 -32
  44. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +0 -28
  45. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +0 -38
@@ -1,475 +0,0 @@
1
- import crypto from 'crypto';
2
- import { proto } from '../../WAProto/index.js';
3
- import { generateWAMessageFromContent, prepareWAMessageMedia } from '../Utils/index.js';
4
-
5
- export const makeMessageBuilderSocket = (sock) => {
6
- const { relayMessage, sendMessage, waUploadToServer } = sock;
7
-
8
- // per-socket-instance poll state: id -> [{ vote, action }]
9
- const pollActionStore = new Map();
10
-
11
- /**
12
- * Relay an arbitrary raw message content object, bypassing the normal
13
- * content-type detection in sendMessage(). Useful when you've already
14
- * built a proto-shaped message (e.g. from generateWAMessageFromContent)
15
- * and just need it sent as-is.
16
- */
17
- const sendJsonMessage = async (jid, content = {}, options = {}) => {
18
- const msg = generateWAMessageFromContent(jid, content, {});
19
- return relayMessage(jid, msg.message, { messageId: msg.key.id, ...options });
20
- };
21
-
22
- /**
23
- * Sends a WA poll and remembers which "action" each option maps to, so
24
- * a caller can look up what the voter selected once the vote comes back
25
- * through a `messages.update` event (see resolvePollAction below).
26
- *
27
- * pollOptions: [{ vote: 'Option label', action: 'anything you want back' }]
28
- */
29
- const sendActionPoll = async (jid, name = '', pollOptions = [], options = {}) => {
30
- const values = pollOptions.map(o => o.vote);
31
- const pollMsg = await sendMessage(jid, { poll: { name, values, selectableCount: options.selectableCount || 1 } }, options);
32
- pollActionStore.set(pollMsg.key.id, pollOptions);
33
- return pollMsg;
34
- };
35
-
36
- /**
37
- * Given a poll creation message id and the selected option label (as
38
- * resolved via getAggregateVotesInPollMessage), returns the `action`
39
- * that was registered for it in sendActionPoll, or undefined if this
40
- * poll wasn't created through sendActionPoll (or already forgotten).
41
- */
42
- const resolvePollAction = (pollMessageId, selectedVoteLabel) => {
43
- const options = pollActionStore.get(pollMessageId);
44
- return options?.find(o => o.vote === selectedVoteLabel)?.action;
45
- };
46
-
47
- /**
48
- * Sends a set of media files as a single WA album (grouped gallery).
49
- * media: array of local file paths or URLs; extension picks image/video.
50
- */
51
- const sendAlbumMessage = async (jid, media = [], contextInfo = {}) => {
52
- const albumMsg = generateWAMessageFromContent(jid, proto.Message.fromObject({
53
- albumMessage: {
54
- expectedImageCount: media.filter(m => !/\.mp4$/i.test(m)).length,
55
- expectedVideoCount: media.filter(m => /\.mp4$/i.test(m)).length,
56
- contextInfo
57
- }
58
- }), {});
59
-
60
- const albumKey = {
61
- id: await relayMessage(jid, albumMsg.message, { messageId: albumMsg.key.id }),
62
- remoteJid: jid,
63
- fromMe: true
64
- };
65
-
66
- const keys = { album: albumKey };
67
- let i = 1;
68
-
69
- const mimetypes = {
70
- jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png',
71
- gif: 'image/gif', webp: 'image/webp', mp4: 'video/mp4'
72
- };
73
- const messagetypes = {
74
- jpg: 'imageMessage', jpeg: 'imageMessage', png: 'imageMessage',
75
- gif: 'imageMessage', webp: 'imageMessage', mp4: 'videoMessage'
76
- };
77
-
78
- for (const source of media) {
79
- const ext = source.split('.').pop().toLowerCase();
80
- const mimetype = mimetypes[ext];
81
- const type = messagetypes[ext];
82
-
83
- if (!mimetype || !type) {
84
- continue;
85
- }
86
-
87
- const msg = await prepareWAMessageMedia(
88
- { [type.startsWith('image') ? 'image' : 'video']: { url: source }, mimetype },
89
- { upload: waUploadToServer }
90
- );
91
-
92
- const mediaMessage = generateWAMessageFromContent(jid, proto.Message.fromObject({
93
- associatedChildMessage: {
94
- message: {
95
- messageContextInfo: {
96
- messageSecret: crypto.randomBytes(32),
97
- messageAssociation: {
98
- associationType: 'MEDIA_ALBUM',
99
- parentMessageKey: albumKey
100
- }
101
- },
102
- [type]: { ...msg[type] }
103
- }
104
- }
105
- }), {});
106
-
107
- keys[`media_${i++}`] = {
108
- id: await relayMessage(jid, mediaMessage.message, { messageId: mediaMessage.key.id }),
109
- fromMe: true,
110
- remoteJid: jid
111
- };
112
- }
113
-
114
- return keys;
115
- };
116
-
117
- /**
118
- * Posts `content` to status@broadcast and mentions `jid` in it (i.e. a
119
- * status update that notifies a specific contact).
120
- */
121
- const sendStatusMention = async (jid, content) => {
122
- const media = generateWAMessageFromContent('status@broadcast', content, {});
123
-
124
- const additionalNodes = [
125
- {
126
- tag: 'meta',
127
- attrs: {},
128
- content: [
129
- {
130
- tag: 'mentioned_users',
131
- attrs: {},
132
- content: [{ tag: 'to', attrs: { jid }, content: undefined }]
133
- }
134
- ]
135
- }
136
- ];
137
-
138
- await relayMessage('status@broadcast', media.message, {
139
- messageId: media.key.id,
140
- statusJidList: [jid, sock.user?.id],
141
- additionalNodes
142
- });
143
-
144
- return media;
145
- };
146
-
147
- /**
148
- * Builds and sends a "rich response" card (WA's GenAI-style unified
149
- * response widget: optional header image/title, body buttons or a
150
- * carousel/row of cards, and an optional footer link).
151
- *
152
- * content.header: { title, image: { url, mime_type, inline, width, height }, disclaimer, disclaimerText }
153
- * content.body: { title, buttons: [labels] } OR { carousel|row: true, cards: [{ title, buttons, toast }] }
154
- * content.footer: { text, url, image }
155
- */
156
- const sendRichResponse = async (jid, content = {}) => {
157
- const header = content?.header;
158
- const body = content?.body;
159
- const footer = content?.footer;
160
- let messageContextInfo = {};
161
- const sections = [];
162
-
163
- if (header) {
164
- const { disclaimer = false, disclaimerText = ' ', image = { inline: false }, title = '' } = header ?? {};
165
-
166
- if (disclaimer) {
167
- messageContextInfo = { messageContextInfo: { botMetadata: { messageDisclaimerText: disclaimerText } } };
168
- }
169
-
170
- if (title) {
171
- sections.push({
172
- __typename: 'GenAIUnifiedResponseSection',
173
- view_model: {
174
- __typename: 'GenAISingleLayoutViewModel',
175
- primitive: { __typename: 'FOATextPrimitive', text: '# ' + title }
176
- }
177
- });
178
- }
179
-
180
- if (image?.url) {
181
- sections.push(image.inline ? {
182
- __typename: 'GenAIUnifiedResponseSection',
183
- view_model: {
184
- __typename: 'GenAISingleLayoutViewModel',
185
- primitive: {
186
- __typename: 'GenAIMarkdownTextUXPrimitive',
187
- text: '{{header}}.{{/header}}',
188
- inline_entities: [{
189
- __typename: 'GenAITextInlineEntity',
190
- key: 'header',
191
- metadata: {
192
- __typename: 'GenAILatexItem',
193
- latex_expression: '.',
194
- font_height: 24,
195
- padding: 4,
196
- latex_image: {
197
- __typename: 'GenAIMediaItem',
198
- mime_type: image.mime_type || 'image/png',
199
- url: image.url,
200
- url_fallback: image.url,
201
- width: image.width || 500,
202
- height: image.height || 500,
203
- expiration_timestamp_ms: Date.now() + 86400000
204
- }
205
- }
206
- }]
207
- }
208
- }
209
- } : {
210
- __typename: 'GenAIUnifiedResponseSection',
211
- view_model: {
212
- __typename: 'GenAISingleLayoutViewModel',
213
- primitive: {
214
- __typename: 'GenAIImagePrimitive',
215
- preview_image: { __typename: 'GenAIMediaItem', mime_type: image.mime_type || 'image/png', url: image.url },
216
- full_image: { __typename: 'GenAIMediaItem', mime_type: image.mime_type || 'image/png', url: image.url }
217
- }
218
- }
219
- });
220
- }
221
- }
222
-
223
- if (body) {
224
- const { cards = null, buttons = null, title = '', toast = '', carousel = false, row = false } = body ?? {};
225
-
226
- if ((carousel || row) && cards?.length >= 1) {
227
- sections.push({
228
- __typename: 'GenAIUnifiedResponseSection',
229
- view_model: {
230
- primitives: cards.map((card, cardIndex) => ({
231
- __typename: 'GenAI3PExtWidgetPrimitive',
232
- header: { __typename: 'GenAI3PExtWidgetStandardHeader', title: card?.title || '' },
233
- body: {
234
- __typename: 'GenAI3PExtCalendarEventList',
235
- ctas: (card?.buttons || []).map((text, buttonIndex) => ({
236
- label: text,
237
- state: 'PENDING',
238
- kind: 'OTHER',
239
- tool_call_id: `${cardIndex}${buttonIndex}`,
240
- toast: { label: card?.toast || '', __typename: 'GenAI3PExtWidgetToast' },
241
- __typename: 'GenAI3PExtWidgetCTA'
242
- })),
243
- sections: []
244
- }
245
- })),
246
- __typename: carousel ? 'GenAIHScrollLayoutViewModel' : 'GenAIActionRowLayoutViewModel'
247
- }
248
- });
249
- } else if (buttons?.length) {
250
- sections.push({
251
- __typename: 'GenAIUnifiedResponseSection',
252
- view_model: {
253
- primitive: {
254
- __typename: 'GenAI3PExtWidgetPrimitive',
255
- header: { __typename: 'GenAI3PExtWidgetStandardHeader', title: title || '' },
256
- body: {
257
- __typename: 'GenAI3PExtCalendarEventList',
258
- ctas: buttons.map((text, buttonIndex) => ({
259
- label: text,
260
- state: 'PENDING',
261
- kind: 'OTHER',
262
- tool_call_id: `${buttonIndex}`,
263
- toast: { label: toast, __typename: 'GenAI3PExtWidgetToast' },
264
- __typename: 'GenAI3PExtWidgetCTA'
265
- })),
266
- sections: []
267
- }
268
- },
269
- __typename: 'GenAISingleLayoutViewModel'
270
- }
271
- });
272
- }
273
- }
274
-
275
- if (footer) {
276
- const { text = '', url = '', image = {} } = footer ?? {};
277
- const img = [];
278
- if (image?.url) {
279
- img.push({
280
- __typename: 'GenAIMarkdownTextUXPrimitive',
281
- text: '{{header}}.{{/header}}',
282
- inline_entities: [{
283
- __typename: 'GenAITextInlineEntity',
284
- key: 'header',
285
- metadata: {
286
- __typename: 'GenAILatexItem',
287
- latex_expression: '.',
288
- font_height: 24,
289
- padding: -5,
290
- latex_image: {
291
- __typename: 'GenAIMediaItem',
292
- mime_type: image.mime_type || 'image/png',
293
- url: image.url,
294
- url_fallback: image.url,
295
- width: image.width || 100,
296
- height: image.height || 100,
297
- expiration_timestamp_ms: Date.now() + 86400000
298
- }
299
- }
300
- }]
301
- });
302
- }
303
- sections.push({
304
- view_model: {
305
- primitives: [
306
- { cta_text: text || '', cta_type: 'OPEN_URL', cta_url: url || '', __typename: 'GenAIFooterActionPrimitive' },
307
- ...img
308
- ],
309
- __typename: 'GenAIActionRowLayoutViewModel'
310
- }
311
- });
312
- }
313
-
314
- return sendJsonMessage(jid, {
315
- ...messageContextInfo,
316
- richResponseMessage: {
317
- unifiedResponse: { data: Buffer.from(JSON.stringify({ sections })).toString('base64') },
318
- contextInfo: content?.contextInfo ?? {}
319
- }
320
- });
321
- };
322
-
323
- /**
324
- * Sends a native quick-reply buttons message.
325
- * buttons: [{ id: 'unique_id', text: 'Label' }]
326
- */
327
- const sendButtonsMessage = async (jid, { text = '', footer = '', buttons = [] } = {}, options = {}) => {
328
- const interactiveMessage = {
329
- body: { text },
330
- ...(footer ? { footer: { text: footer } } : {}),
331
- nativeFlowMessage: {
332
- buttons: buttons.map(b => ({
333
- name: b.name || 'quick_reply',
334
- buttonParamsJson: JSON.stringify({ display_text: b.text, id: b.id })
335
- }))
336
- }
337
- };
338
- return sendJsonMessage(jid, { viewOnceMessage: { message: { interactiveMessage } } }, options);
339
- };
340
-
341
- /**
342
- * Sends a native single-select list message.
343
- * sections: [{ title: 'Section', rows: [{ title, description, id }] }]
344
- */
345
- const sendListMessage = async (jid, { text = '', footer = '', buttonText = 'Menu', sections = [] } = {}, options = {}) => {
346
- const interactiveMessage = {
347
- body: { text },
348
- ...(footer ? { footer: { text: footer } } : {}),
349
- nativeFlowMessage: {
350
- buttons: [{
351
- name: 'single_select',
352
- buttonParamsJson: JSON.stringify({ title: buttonText, sections })
353
- }]
354
- }
355
- };
356
- return sendJsonMessage(jid, { viewOnceMessage: { message: { interactiveMessage } } }, options);
357
- };
358
-
359
- /**
360
- * Sends a native horizontal-scroll carousel of cards (the correct native
361
- * mechanism for side-by-side buttons — unlike the GenAI rich-response
362
- * widget, which is designed as a vertical list).
363
- * cards: [{ image: 'url or local path', mimetype, title, body, buttons: [{ id, text }] }]
364
- */
365
- const sendCarouselMessage = async (jid, { text = '', footer = '', cards = [] } = {}, options = {}) => {
366
- const cardMessages = [];
367
-
368
- for (const card of cards) {
369
- let headerMedia = {};
370
- if (card.image) {
371
- const uploaded = await prepareWAMessageMedia(
372
- { image: { url: card.image }, mimetype: card.mimetype || 'image/jpeg' },
373
- { upload: waUploadToServer }
374
- );
375
- headerMedia = { imageMessage: uploaded.imageMessage };
376
- }
377
-
378
- cardMessages.push({
379
- header: { title: card.title || '', hasMediaAttachment: !!card.image, ...headerMedia },
380
- body: { text: card.body || '' },
381
- nativeFlowMessage: {
382
- buttons: (card.buttons || []).map(b => ({
383
- name: b.name || 'quick_reply',
384
- buttonParamsJson: JSON.stringify({ display_text: b.text, id: b.id })
385
- }))
386
- }
387
- });
388
- }
389
-
390
- const message = {
391
- viewOnceMessage: {
392
- message: {
393
- interactiveMessage: {
394
- body: { text },
395
- ...(footer ? { footer: { text: footer } } : {}),
396
- carouselMessage: { cards: cardMessages, messageVersion: 1 }
397
- }
398
- }
399
- }
400
- };
401
- return sendJsonMessage(jid, message, options);
402
- };
403
-
404
- /**
405
- * Forwards an existing message (e.g. one pulled from the store) to
406
- * another chat. Delegates to the library's own forward content builder
407
- * (sendMessage's `forward` content type) so conversation→extendedText
408
- * conversion, forwardingScore, and isForwarded are handled correctly
409
- * instead of being reimplemented here.
410
- */
411
- const forwardMessage = async (jid, message, options = {}) => {
412
- return sendMessage(jid, { forward: message, force: options.force }, options);
413
- };
414
-
415
- /**
416
- * Builds a proper vCard string and sends it as a contact message.
417
- * contact: { name, phone (E.164, no '+'), organization, waid }
418
- * If multiple contacts are given, sends a contactsArrayMessage.
419
- */
420
- const sendVCard = async (jid, contacts, options = {}) => {
421
- const list = Array.isArray(contacts) ? contacts : [contacts];
422
- const built = list.map(c => {
423
- const waid = c.waid || c.phone;
424
- const vcard = 'BEGIN:VCARD\n'
425
- + 'VERSION:3.0\n'
426
- + `FN:${c.name || 'Unknown'}\n`
427
- + (c.organization ? `ORG:${c.organization};\n` : '')
428
- + `TEL;type=CELL;type=VOICE;waid=${waid}:+${c.phone}\n`
429
- + 'END:VCARD';
430
- return { displayName: c.name || 'Unknown', vcard };
431
- });
432
-
433
- if (built.length === 1) {
434
- return sendMessage(jid, { contacts: { contacts: built } }, options);
435
- }
436
- return sendMessage(jid, { contacts: { displayName: `${built.length} contacts`, contacts: built } }, options);
437
- };
438
-
439
- /**
440
- * Sends the same content to a list of jids sequentially, with an
441
- * optional delay between sends (helps avoid rate limiting). Returns
442
- * an array of { jid, ok, result|error } for each recipient.
443
- * options.delayMs is stripped before being passed to sendMessage.
444
- */
445
- const broadcastMessage = async (jids, content, options = {}) => {
446
- const { delayMs = 0, ...sendOptions } = options;
447
- const results = [];
448
- for (const jid of jids) {
449
- try {
450
- const result = await sendMessage(jid, content, sendOptions);
451
- results.push({ jid, ok: true, result });
452
- } catch (error) {
453
- results.push({ jid, ok: false, error });
454
- }
455
- if (delayMs) await new Promise(resolve => setTimeout(resolve, delayMs));
456
- }
457
- return results;
458
- };
459
-
460
- return {
461
- ...sock,
462
- sendJsonMessage,
463
- sendActionPoll,
464
- resolvePollAction,
465
- sendAlbumMessage,
466
- sendStatusMention,
467
- sendRichResponse,
468
- sendButtonsMessage,
469
- sendListMessage,
470
- sendCarouselMessage,
471
- forwardMessage,
472
- sendVCard,
473
- broadcastMessage
474
- };
475
- };