@nexustechpro/baileys 1.1.2 → 1.1.3

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.
@@ -91,6 +91,7 @@ export const MEDIA_HKDF_KEY_MAPPING = {
91
91
  ppic: '',
92
92
  product: 'Image',
93
93
  ptt: 'Audio',
94
+ 'sticker-pack-publisher': 'Sticker Pack Publisher',
94
95
  sticker: 'Image',
95
96
  'sticker-pack': 'Sticker Pack',
96
97
  'thumbnail-sticker-pack': 'Sticker Pack Thumbnail',
@@ -23,7 +23,7 @@ const {
23
23
  const {
24
24
  areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser,
25
25
  isJidGroup, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, S_WHATSAPP_NET,
26
- getBinaryFilteredButtons, STORIES_JID, isJidUser, isJidNewsletter
26
+ getBinaryFilteredButtons, STORIES_JID, isJidUser, isJidNewsletter, getButtonArgs, getButtonType
27
27
  } = WABinary
28
28
 
29
29
  export const makeMessagesSocket = (config) => {
@@ -366,61 +366,6 @@ export const makeMessagesSocket = (config) => {
366
366
  if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) return 'url'
367
367
  }
368
368
 
369
- const getButtonType = (message) => {
370
- if (message.listMessage) return 'list'
371
- if (message.buttonsMessage) return 'buttons'
372
- const btn = message.interactiveMessage?.nativeFlowMessage?.buttons?.[0]?.name
373
- if (['review_and_pay', 'review_order', 'payment_info', 'payment_status', 'payment_method'].includes(btn)) return btn
374
- if (message.interactiveMessage?.nativeFlowMessage) return 'interactive'
375
- }
376
-
377
- const getButtonArgs = (message) => {
378
- const msgContent = message.viewOnceMessage?.message || message
379
- const flowMsg = msgContent.interactiveMessage?.nativeFlowMessage
380
- const btnFirst = flowMsg?.buttons?.[0]?.name
381
- const specialBtns = ['mpm', 'cta_catalog', 'send_location', 'call_permission_request', 'wa_payment_transaction_details', 'automated_greeting_message_view_catalog']
382
-
383
- const base = {
384
- tag: 'biz',
385
- attrs: { actual_actors: '2', host_storage: '2', privacy_mode_ts: unixTimestampSeconds().toString() }
386
- }
387
-
388
- if (flowMsg && (btnFirst === 'review_and_pay' || btnFirst === 'payment_info')) {
389
- return { tag: 'biz', attrs: { native_flow_name: btnFirst === 'review_and_pay' ? 'order_details' : btnFirst } }
390
- }
391
-
392
- if (flowMsg && specialBtns.includes(btnFirst)) {
393
- return {
394
- ...base,
395
- content: [
396
- { tag: 'interactive', attrs: { type: 'native_flow', v: '1' }, content: [{ tag: 'native_flow', attrs: { v: '2', name: btnFirst } }] },
397
- { tag: 'quality_control', attrs: { source_type: 'third_party' } }
398
- ]
399
- }
400
- }
401
-
402
- if (flowMsg || msgContent.buttonsMessage) {
403
- return {
404
- ...base,
405
- content: [
406
- { tag: 'interactive', attrs: { type: 'native_flow', v: '1' }, content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }] },
407
- { tag: 'quality_control', attrs: { source_type: 'third_party' } }
408
- ]
409
- }
410
- }
411
-
412
- if (msgContent.listMessage) {
413
- return {
414
- ...base,
415
- content: [
416
- { tag: 'list', attrs: { v: '2', type: 'product_list' } },
417
- { tag: 'quality_control', attrs: { source_type: 'third_party' } }
418
- ]
419
- }
420
- }
421
-
422
- return base
423
- }
424
369
 
425
370
  // ===== CORE MESSAGE RELAY =====
426
371
  const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList } = {}) => {
@@ -905,6 +850,14 @@ export const makeMessagesSocket = (config) => {
905
850
  const userJid = authState.creds.me.id
906
851
  const { quoted } = options
907
852
 
853
+ // Handle interactive messages sent with 'interactive' key
854
+ // Convert to 'interactiveMessage' for nexus detection
855
+ if (content.interactive && !content.interactiveMessage) {
856
+ // Merge other content with interactiveMessage
857
+ const { interactive, ...otherContent } = content
858
+ content = { ...otherContent, interactiveMessage: interactive }
859
+ }
860
+
908
861
  // Check if nexus can handle this message type
909
862
  const messageType = nexus.detectType(content)
910
863
  if (messageType) return await nexus.processMessage(content, jid, quoted)
@@ -38,6 +38,7 @@ class NexusHandler {
38
38
  requestPaymentMessage: 'PAYMENT',
39
39
  productMessage: 'PRODUCT',
40
40
  interactiveMessage: 'INTERACTIVE',
41
+ interactive: 'INTERACTIVE', // Also detect 'interactive' key
41
42
  albumMessage: 'ALBUM',
42
43
  eventMessage: 'EVENT',
43
44
  pollResultMessage: 'POLL_RESULT',
@@ -73,7 +74,7 @@ class NexusHandler {
73
74
  }
74
75
 
75
76
  async genContent(jid, content, opts = {}) {
76
- return await this.utils.generateWAMessageFromContent(jid, content, { ...opts, upload: this.upload })
77
+ return await this.utils.generateWAMessage(jid, content, { ...opts, upload: this.upload })
77
78
  }
78
79
 
79
80
  async sendMsg(jid, message, opts = {}) {
@@ -164,7 +165,8 @@ class NexusHandler {
164
165
  }
165
166
 
166
167
  async handleInteractive(content, jid, quoted) {
167
- const i = content.interactiveMessage || {}
168
+ // Handle both 'interactiveMessage' and 'interactive' keys
169
+ const i = content.interactiveMessage || content.interactive || {}
168
170
  let media = null
169
171
 
170
172
  if (i.thumbnail) media = await this.prepMedia({ url: i.thumbnail }, 'image')
@@ -177,10 +179,22 @@ class NexusHandler {
177
179
  if (i.mimetype) media.documentMessage.mimetype = i.mimetype
178
180
  }
179
181
 
180
- const interactive = { body: { text: i.title || '' }, footer: { text: i.footer || '' } }
182
+ // Handle both formats: { title, footer } and { body: {text}, footer: {text} }
183
+ const bodyText = i.body?.text || i.title || ''
184
+ const footerText = i.footer?.text || i.footer || ''
185
+ const interactive = { body: { text: bodyText }, footer: { text: footerText } }
181
186
 
182
187
  if (i.buttons?.length || i.nativeFlowMessage) {
183
- interactive.nativeFlowMessage = { buttons: i.buttons || [], ...(i.nativeFlowMessage || {}) }
188
+ // Build nativeFlowMessage with proper structure
189
+ const nativeFlow = i.nativeFlowMessage || {}
190
+ // Only include buttons, don't add empty messageParamsJson
191
+ interactive.nativeFlowMessage = {
192
+ buttons: i.buttons || nativeFlow.buttons || []
193
+ }
194
+ // Only add messageParamsJson if explicitly provided
195
+ if (nativeFlow.messageParamsJson) {
196
+ interactive.nativeFlowMessage.messageParamsJson = nativeFlow.messageParamsJson
197
+ }
184
198
  }
185
199
 
186
200
  if (media) {
@@ -188,15 +202,23 @@ class NexusHandler {
188
202
  if (media.imageMessage) headerMedia.imageMessage = media.imageMessage
189
203
  if (media.videoMessage) headerMedia.videoMessage = media.videoMessage
190
204
  if (media.documentMessage) headerMedia.documentMessage = media.documentMessage
191
- interactive.header = { title: i.header || '', hasMediaAttachment: true, ...headerMedia }
205
+ // Handle both plain title string and full header object
206
+ const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
207
+ interactive.header = { title: headerTitle, hasMediaAttachment: true, ...headerMedia }
192
208
  } else {
193
- interactive.header = { title: i.header || '', hasMediaAttachment: false }
209
+ // Handle both plain title string and full header object
210
+ const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
211
+ interactive.header = { title: headerTitle, hasMediaAttachment: false }
194
212
  }
195
213
 
196
214
  const ctx = this.buildFullCtx(i.contextInfo, i.externalAdReply)
197
215
  if (Object.keys(ctx).length) interactive.contextInfo = ctx
198
216
 
199
- const msg = await this.genContent(jid, { interactiveMessage: interactive }, { quoted })
217
+ // Return interactiveMessage directly without wrapping for native flows
218
+ // This matches fadzzz404's approach which works correctly
219
+ const messageContent = { interactiveMessage: interactive }
220
+
221
+ const msg = await this.genContent(jid, messageContent, { quoted })
200
222
  await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
201
223
  return msg
202
224
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
- export * from '@nexustechpro/baileys/lib/Store/make-cache-manager-store.js';
3
- export * from '@nexustechpro/baileys/lib/Store/make-in-memory-store.js';
4
- export * from '@nexustechpro/baileys/lib/Store/make-ordered-dictionary.js';
5
- export * from '@nexustechpro/baileys/lib/Store/object-repository.js';
6
- export { makeInMemoryStore as default } from '@nexustechpro/baileys/lib/Store/make-in-memory-store.js';
2
+ export * from './make-cache-manager-store.js';
3
+ export * from './make-in-memory-store.js';
4
+ export * from './make-ordered-dictionary.js';
5
+ export * from './make-ordered-dictionary.js';
6
+ export { makeInMemoryStore as default } from './make-in-memory-store.js';
@@ -3,8 +3,8 @@ import * as Defaults from '../Defaults/index.js';
3
3
  import { LabelAssociationType } from '../Types/LabelAssociation.js';
4
4
  import { md5, toNumber } from '../Utils/index.js';
5
5
  import { jidDecode, jidNormalizedUser } from '../WABinary/index.js';
6
- import { makeOrderedDictionary } from '@nexustechpro/baileys/lib/Store/make-ordered-dictionary.js';
7
- import { ObjectRepository } from '@nexustechpro/baileys/lib/Store/object-repository.js';
6
+ import { makeOrderedDictionary } from './make-ordered-dictionary.js';
7
+ import { ObjectRepository } from './object-repository.js';
8
8
 
9
9
  const waChatKey = (pin) => ({
10
10
  key: (c) => (pin ? (c.pinned ? '1' : '0') : '') + (c.archived ? '0' : '1') + (c.conversationTimestamp ? c.conversationTimestamp.toString(16).padStart(8, '0') : '') + c.id,
@@ -53,7 +53,40 @@ export const generateParticipantHashV2 = (participants) => {
53
53
  const sha256Hash = sha256(Buffer.from(participants.join(''))).toString('base64');
54
54
  return '2:' + sha256Hash.slice(0, 6);
55
55
  };
56
- export const encodeWAMessage = (message) => writeRandomPadMax16(proto.Message.encode(message).finish());
56
+
57
+ /**
58
+ * Encode a WhatsApp message to protobuf format
59
+ * Handles both raw JSON objects and pre-created protobuf objects seamlessly for ANY message type
60
+ * @param {Object|proto.Message} message - Raw message object or protobuf Message
61
+ * @returns {Buffer} Encoded message with random padding
62
+ */
63
+ export const encodeWAMessage = (message) => {
64
+ try {
65
+ // Check if message is already a protobuf Message instance
66
+ if (message && typeof message === 'object' && message.$type === proto.Message) {
67
+ // Already a protobuf object, encode directly
68
+ return writeRandomPadMax16(proto.Message.encode(message).finish());
69
+ }
70
+
71
+ // Convert raw JSON object to protobuf Message
72
+ if (message && typeof message === 'object') {
73
+ // Use proto.Message.fromObject for automatic conversion
74
+ const protoMessage = proto.Message.fromObject(message);
75
+ return writeRandomPadMax16(proto.Message.encode(protoMessage).finish());
76
+ }
77
+
78
+ // Fallback for edge cases
79
+ return writeRandomPadMax16(proto.Message.encode(message).finish());
80
+ } catch (error) {
81
+ // If conversion fails, attempt direct encoding as last resort
82
+ try {
83
+ return writeRandomPadMax16(proto.Message.encode(message).finish());
84
+ } catch (e) {
85
+ console.warn('Message encoding failed:', error.message, e.message);
86
+ throw new Error(`Failed to encode message: ${error.message}`);
87
+ }
88
+ }
89
+ };
57
90
  export const generateRegistrationId = () => {
58
91
  return Uint16Array.from(randomBytes(2))[0] & 16383;
59
92
  };
@@ -202,9 +202,14 @@ const handleSpecialMessages = async (message, options) => {
202
202
  : message.disappearingMessagesInChat;
203
203
  return prepareDisappearingMessageSettingContent(exp);
204
204
  }
205
+ if ('extendedTextMessage' in message) { return { extendedTextMessage: message.extendedTextMessage } };
206
+ if ('interactiveMessage' in message) {
207
+ return { interactiveMessage: WAProto.Message.InteractiveMessage.create(message.interactiveMessage) };
208
+ }
205
209
  return null;
206
210
  };
207
211
 
212
+
208
213
  const handleGroupInvite = async (message, options) => {
209
214
  const m = {
210
215
  groupInviteMessage: {
@@ -350,6 +355,7 @@ export const generateWAMessageContent = async (message, options) => {
350
355
  }
351
356
  };
352
357
  else if ('requestPayment' in message) m = await handleRequestPayment(message, options);
358
+ else if ('extendedTextMessage' in message) { m = { extendedTextMessage: message.extendedTextMessage }; }
353
359
  else if ('sharePhoneNumber' in message) m = { protocolMessage: { type: 4 } };
354
360
  else if ('requestPhoneNumber' in message) m = { requestPhoneNumberMessage: {} };
355
361
  else if ('limitSharing' in message) m = {
@@ -387,6 +393,7 @@ export const generateWAMessageContent = async (message, options) => {
387
393
  return WAProto.Message.create(m);
388
394
  };
389
395
 
396
+
390
397
  export const generateWAMessageFromContent = (jid, message, options) => {
391
398
  if (!options.timestamp) options.timestamp = new Date();
392
399
  const innerMessage = normalizeMessageContent(message);
@@ -651,5 +658,4 @@ export const assertMediaContent = (content) => {
651
658
  const mediaContent = content?.documentMessage || content?.imageMessage || content?.videoMessage || content?.audioMessage || content?.stickerMessage;
652
659
  if (!mediaContent) throw new Boom('given message is not a media message', { statusCode: 400, data: content });
653
660
  return mediaContent;
654
- };
655
-
661
+ };
@@ -25,6 +25,100 @@ export const getBinaryNodeChildBuffer = (node, childTag) => {
25
25
  return child;
26
26
  }
27
27
  };
28
+ // Add this function after getBinaryFilteredButtons
29
+ export const getButtonArgs = (message) => {
30
+ const msgContent = message.viewOnceMessage?.message || message;
31
+ // Check both interactiveMessage and interactive keys
32
+ const interactiveMsg = msgContent.interactiveMessage || msgContent.interactive;
33
+ const flowMsg = interactiveMsg?.nativeFlowMessage;
34
+ const btnFirst = flowMsg?.buttons?.[0]?.name;
35
+ const specialBtns = [
36
+ 'mpm', 'cta_catalog', 'send_location', 'call_permission_request',
37
+ 'wa_payment_transaction_details', 'automated_greeting_message_view_catalog',
38
+ 'open_webview', 'galaxy_message'
39
+ ];
40
+
41
+ const base = {
42
+ tag: 'biz',
43
+ attrs: {
44
+ actual_actors: '2',
45
+ host_storage: '2',
46
+ privacy_mode_ts: Math.floor(Date.now() / 1000).toString()
47
+ }
48
+ };
49
+
50
+ // Special buttons need full interactive structure
51
+ if (flowMsg && specialBtns.includes(btnFirst)) {
52
+ return {
53
+ ...base,
54
+ content: [
55
+ {
56
+ tag: 'interactive',
57
+ attrs: { type: 'native_flow', v: '1' },
58
+ content: [{
59
+ tag: 'native_flow',
60
+ attrs: { v: '2', name: btnFirst }
61
+ }]
62
+ },
63
+ { tag: 'quality_control', attrs: { source_type: 'third_party' } }
64
+ ]
65
+ };
66
+ }
67
+
68
+ // Regular interactive/button messages
69
+ if (flowMsg || msgContent.buttonsMessage) {
70
+ return {
71
+ ...base,
72
+ content: [
73
+ {
74
+ tag: 'interactive',
75
+ attrs: { type: 'native_flow', v: '1' },
76
+ content: [{
77
+ tag: 'native_flow',
78
+ attrs: { v: '9', name: 'mixed' }
79
+ }]
80
+ },
81
+ { tag: 'quality_control', attrs: { source_type: 'third_party' } }
82
+ ]
83
+ };
84
+ }
85
+
86
+ // List messages
87
+ if (msgContent.listMessage) {
88
+ return {
89
+ ...base,
90
+ content: [
91
+ { tag: 'list', attrs: { v: '2', type: 'product_list' } },
92
+ { tag: 'quality_control', attrs: { source_type: 'third_party' } }
93
+ ]
94
+ };
95
+ }
96
+
97
+ return base;
98
+ };
99
+
100
+ // Add button type detection helper
101
+ export const getButtonType = (message) => {
102
+ if (message.listMessage) return 'list';
103
+ if (message.buttonsMessage) return 'buttons';
104
+
105
+ // Check both interactiveMessage and interactive keys
106
+ const interactiveMsg = message.interactiveMessage || message.interactive;
107
+ if (!interactiveMsg?.nativeFlowMessage) return null;
108
+
109
+ const btn = interactiveMsg?.nativeFlowMessage?.buttons?.[0]?.name;
110
+ if (['review_and_pay', 'review_order', 'payment_info', 'payment_status', 'payment_method'].includes(btn)) {
111
+ return btn;
112
+ }
113
+
114
+ // Return 'interactive' for ANY native flow message that has buttons or nativeFlowMessage
115
+ if (interactiveMsg?.nativeFlowMessage?.buttons?.length || interactiveMsg?.nativeFlowMessage) {
116
+ return 'interactive';
117
+ }
118
+
119
+ return null;
120
+ };
121
+
28
122
  export const getBinaryNodeChildString = (node, childTag) => {
29
123
  const child = getBinaryNodeChild(node, childTag)?.content;
30
124
  if (Buffer.isBuffer(child) || child instanceof Uint8Array) {
package/lib/index.js CHANGED
@@ -31,7 +31,7 @@ const banner = `
31
31
  const info = `
32
32
  ┌───────────────────────────────────────────────────────────────────────┐
33
33
  │ 📦 Package: @nexustechpro/baileys │
34
- │ 🔖 Version: 1.1.2
34
+ │ 🔖 Version: 1.1.3
35
35
  │ ⚡ Status: Production Ready │
36
36
  ├───────────────────────────────────────────────────────────────────────┤
37
37
  │ 🚀 Advanced WhatsApp Web API Client │
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexustechpro/baileys",
3
3
  "type": "module",
4
- "version": "1.1.2",
4
+ "version": "1.1.3",
5
5
  "description": "Advanced WhatsApp Web API client with interactive messages, product catalogs, carousels, events, payments, and polls.",
6
6
  "keywords": [
7
7
  "whatsapp",
@@ -51,6 +51,7 @@
51
51
  "@cacheable/node-cache": "^1.4.0",
52
52
  "@hapi/boom": "^9.1.3",
53
53
  "async-mutex": "^0.5.0",
54
+ "axios": "^1.6.0",
54
55
  "cache-manager": "latest",
55
56
  "chalk": "^4.1.2",
56
57
  "gradient-string": "^2.0.2",