waengine 2.3.9 → 2.3.10
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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/advanced-features.js +97 -61
- package/src/ui-components.js +149 -80
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ client.on('truly_connected', (data) => {
|
|
|
100
100
|
- **Button Messages** - Interactive buttons with callbacks
|
|
101
101
|
- **List Messages** - Organized lists with sections
|
|
102
102
|
- **Template Messages** - Reusable message templates
|
|
103
|
-
- **Carousel
|
|
103
|
+
- **Interactive Carousel** - REAL swipeable carousel in ONE message with VIDEO support! 🎬
|
|
104
104
|
|
|
105
105
|
### 👥 **Advanced Group Features**
|
|
106
106
|
- **Group Settings** - Control who can send messages
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waengine",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.10",
|
|
4
4
|
"description": "🚀 WAEngine - The most powerful WhatsApp Bot Library with 860+ Working Features, Complete Baileys Integration & Production-Ready Stability",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
package/src/advanced-features.js
CHANGED
|
@@ -237,73 +237,109 @@ export class AdvancedMessage {
|
|
|
237
237
|
|
|
238
238
|
async sendCarouselMessage(cards) {
|
|
239
239
|
try {
|
|
240
|
-
// WhatsApp Carousel
|
|
241
|
-
const
|
|
240
|
+
// REAL WhatsApp Interactive Carousel - ONE message with swipeable cards!
|
|
241
|
+
const carouselMessage = {
|
|
242
|
+
interactiveMessage: {
|
|
243
|
+
header: {
|
|
244
|
+
title: 'Carousel',
|
|
245
|
+
hasMediaAttachment: false
|
|
246
|
+
},
|
|
247
|
+
body: {
|
|
248
|
+
text: 'Swipe to see all options'
|
|
249
|
+
},
|
|
250
|
+
carouselMessage: {
|
|
251
|
+
cards: cards.map((card, index) => {
|
|
252
|
+
const carouselCard = {
|
|
253
|
+
body: {
|
|
254
|
+
text: card.body || ''
|
|
255
|
+
},
|
|
256
|
+
footer: {
|
|
257
|
+
text: card.footer || `${index + 1}/${cards.length}`
|
|
258
|
+
},
|
|
259
|
+
nativeFlowMessage: {
|
|
260
|
+
buttons: []
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Add header with media (video or image)
|
|
265
|
+
if (card.video) {
|
|
266
|
+
carouselCard.header = {
|
|
267
|
+
title: card.title,
|
|
268
|
+
subtitle: card.subtitle || '',
|
|
269
|
+
hasMediaAttachment: true,
|
|
270
|
+
videoMessage: {
|
|
271
|
+
url: card.video,
|
|
272
|
+
gifPlayback: card.gifPlayback || false
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
} else if (card.image) {
|
|
276
|
+
carouselCard.header = {
|
|
277
|
+
title: card.title,
|
|
278
|
+
subtitle: card.subtitle || '',
|
|
279
|
+
hasMediaAttachment: true,
|
|
280
|
+
imageMessage: {
|
|
281
|
+
url: card.image
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
} else {
|
|
285
|
+
carouselCard.header = {
|
|
286
|
+
title: card.title,
|
|
287
|
+
subtitle: card.subtitle || '',
|
|
288
|
+
hasMediaAttachment: false
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Add buttons
|
|
293
|
+
if (card.buttons && card.buttons.length > 0) {
|
|
294
|
+
carouselCard.nativeFlowMessage.buttons = card.buttons.map(btn => ({
|
|
295
|
+
name: 'quick_reply',
|
|
296
|
+
buttonParamsJson: JSON.stringify({
|
|
297
|
+
display_text: btn.text || btn.title,
|
|
298
|
+
id: btn.id || `btn_${index}`
|
|
299
|
+
})
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return carouselCard;
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
};
|
|
242
308
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
309
|
+
return await this.socket.sendMessage(this.msg.from, carouselMessage);
|
|
310
|
+
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error('❌ Interactive Carousel fehlgeschlagen:', error);
|
|
313
|
+
|
|
314
|
+
// Fallback: List Message (closest to carousel)
|
|
315
|
+
try {
|
|
316
|
+
const listMessage = {
|
|
317
|
+
text: 'Select an option',
|
|
318
|
+
footer: `${cards.length} options available`,
|
|
319
|
+
title: 'Carousel',
|
|
320
|
+
buttonText: 'View Options',
|
|
321
|
+
sections: [{
|
|
322
|
+
title: 'All Options',
|
|
323
|
+
rows: cards.map((card, i) => ({
|
|
324
|
+
title: card.title,
|
|
325
|
+
description: card.body || card.subtitle || '',
|
|
326
|
+
rowId: `carousel_${i}`
|
|
327
|
+
}))
|
|
328
|
+
}]
|
|
329
|
+
};
|
|
251
330
|
|
|
252
|
-
|
|
253
|
-
if (card.buttons && card.buttons.length > 0) {
|
|
254
|
-
cardText += `\n\n**Options:**\n`;
|
|
255
|
-
card.buttons.forEach((btn, btnIndex) => {
|
|
256
|
-
cardText += `${btnIndex + 1}. ${btn.text || btn.title}\n`;
|
|
257
|
-
});
|
|
258
|
-
}
|
|
331
|
+
return await this.socket.sendMessage(this.msg.from, listMessage);
|
|
259
332
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (card.video) {
|
|
263
|
-
// Video card
|
|
264
|
-
result = await this.socket.sendMessage(this.msg.from, {
|
|
265
|
-
video: { url: card.video },
|
|
266
|
-
caption: cardText,
|
|
267
|
-
gifPlayback: card.gifPlayback || false
|
|
268
|
-
});
|
|
269
|
-
} else if (card.image) {
|
|
270
|
-
// Image card
|
|
271
|
-
result = await this.socket.sendMessage(this.msg.from, {
|
|
272
|
-
image: { url: card.image },
|
|
273
|
-
caption: cardText
|
|
274
|
-
});
|
|
275
|
-
} else {
|
|
276
|
-
// Text-only card
|
|
277
|
-
result = await this.msg.reply(cardText);
|
|
278
|
-
}
|
|
333
|
+
} catch (listError) {
|
|
334
|
+
console.error('❌ List fallback fehlgeschlagen:', listError);
|
|
279
335
|
|
|
280
|
-
|
|
336
|
+
// Final fallback: Text
|
|
337
|
+
const fallbackText = cards.map((card, i) =>
|
|
338
|
+
`${i + 1}. **${card.title}**\n${card.body || ''}`
|
|
339
|
+
).join('\n\n');
|
|
281
340
|
|
|
282
|
-
|
|
283
|
-
if (i < cards.length - 1) {
|
|
284
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return results;
|
|
289
|
-
} catch (error) {
|
|
290
|
-
console.error('❌ Carousel Message fehlgeschlagen:', error);
|
|
291
|
-
// Fallback: Sende Cards als Text
|
|
292
|
-
const results = [];
|
|
293
|
-
for (const card of cards) {
|
|
294
|
-
try {
|
|
295
|
-
let cardText = `🎴 **${card.title}**\n`;
|
|
296
|
-
if (card.subtitle) cardText += `${card.subtitle}\n\n`;
|
|
297
|
-
cardText += card.body;
|
|
298
|
-
if (card.footer) cardText += `\n\n_${card.footer}_`;
|
|
299
|
-
|
|
300
|
-
const result = await this.msg.reply(cardText);
|
|
301
|
-
results.push(result);
|
|
302
|
-
} catch (cardError) {
|
|
303
|
-
console.error('❌ Card fehlgeschlagen:', cardError);
|
|
304
|
-
}
|
|
341
|
+
return await this.msg.reply(fallbackText);
|
|
305
342
|
}
|
|
306
|
-
return results;
|
|
307
343
|
}
|
|
308
344
|
}
|
|
309
345
|
}
|
package/src/ui-components.js
CHANGED
|
@@ -6,88 +6,91 @@ export class UIComponents {
|
|
|
6
6
|
// ===== CAROUSEL MESSAGES =====
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Send carousel message with
|
|
10
|
-
*
|
|
9
|
+
* Send REAL carousel message with swipeable cards in ONE message
|
|
10
|
+
* Uses WhatsApp Interactive Message API
|
|
11
11
|
*/
|
|
12
12
|
async sendCarousel(chatId, cards, options = {}) {
|
|
13
13
|
try {
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
// Build proper WhatsApp Interactive Carousel Message
|
|
15
|
+
const carouselMessage = {
|
|
16
|
+
interactiveMessage: {
|
|
17
|
+
header: {
|
|
18
|
+
title: options.title || 'Carousel',
|
|
19
|
+
hasMediaAttachment: false
|
|
20
|
+
},
|
|
21
|
+
body: {
|
|
22
|
+
text: options.body || 'Swipe to see all options'
|
|
23
|
+
},
|
|
24
|
+
footer: {
|
|
25
|
+
text: options.footer || ''
|
|
26
|
+
},
|
|
27
|
+
carouselMessage: {
|
|
28
|
+
cards: cards.map((card, index) => {
|
|
29
|
+
const carouselCard = {
|
|
30
|
+
body: {
|
|
31
|
+
text: card.body || card.description || ''
|
|
32
|
+
},
|
|
33
|
+
footer: {
|
|
34
|
+
text: card.footer || `${index + 1}/${cards.length}`
|
|
35
|
+
},
|
|
36
|
+
nativeFlowMessage: {
|
|
37
|
+
buttons: []
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Add header with media
|
|
42
|
+
if (card.video) {
|
|
43
|
+
carouselCard.header = {
|
|
44
|
+
title: card.title,
|
|
45
|
+
subtitle: card.subtitle || '',
|
|
46
|
+
hasMediaAttachment: true,
|
|
47
|
+
videoMessage: {
|
|
48
|
+
url: card.video,
|
|
49
|
+
gifPlayback: card.gifPlayback || false
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
} else if (card.image) {
|
|
53
|
+
carouselCard.header = {
|
|
54
|
+
title: card.title,
|
|
55
|
+
subtitle: card.subtitle || '',
|
|
56
|
+
hasMediaAttachment: true,
|
|
57
|
+
imageMessage: {
|
|
58
|
+
url: card.image
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
} else {
|
|
62
|
+
carouselCard.header = {
|
|
63
|
+
title: card.title,
|
|
64
|
+
subtitle: card.subtitle || '',
|
|
65
|
+
hasMediaAttachment: false
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add buttons
|
|
70
|
+
if (card.buttons && card.buttons.length > 0) {
|
|
71
|
+
carouselCard.nativeFlowMessage.buttons = card.buttons.map(btn => ({
|
|
72
|
+
name: 'quick_reply',
|
|
73
|
+
buttonParamsJson: JSON.stringify({
|
|
74
|
+
display_text: btn.title || btn.text,
|
|
75
|
+
id: btn.id || `btn_${index}_${btn.title}`
|
|
76
|
+
})
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return carouselCard;
|
|
81
|
+
})
|
|
82
|
+
}
|
|
30
83
|
}
|
|
31
|
-
|
|
32
|
-
carouselText += `\n`;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (options.footer) {
|
|
36
|
-
carouselText += `\n_${options.footer}_`;
|
|
37
|
-
}
|
|
84
|
+
};
|
|
38
85
|
|
|
39
|
-
// Send
|
|
40
|
-
|
|
41
|
-
const card = cards[i];
|
|
42
|
-
|
|
43
|
-
// Build card text
|
|
44
|
-
let cardText = `**${i + 1}/${cards.length}: ${card.title}**\n`;
|
|
45
|
-
if (card.subtitle) cardText += `${card.subtitle}\n`;
|
|
46
|
-
if (card.body) cardText += `${card.body}\n`;
|
|
47
|
-
if (card.price) cardText += `💰 ${card.price}\n`;
|
|
48
|
-
|
|
49
|
-
if (card.buttons && card.buttons.length > 0) {
|
|
50
|
-
cardText += `\nOptions: `;
|
|
51
|
-
card.buttons.forEach((btn, btnIndex) => {
|
|
52
|
-
cardText += `[${btnIndex + 1}] ${btn.title} `;
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (options.footer) {
|
|
57
|
-
cardText += `\n\n_${options.footer}_`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Send with appropriate media type
|
|
61
|
-
if (card.video) {
|
|
62
|
-
// Video card
|
|
63
|
-
await this.client.socket.sendMessage(chatId, {
|
|
64
|
-
video: { url: card.video },
|
|
65
|
-
caption: cardText,
|
|
66
|
-
gifPlayback: card.gifPlayback || false
|
|
67
|
-
});
|
|
68
|
-
} else if (card.image) {
|
|
69
|
-
// Image card
|
|
70
|
-
await this.client.socket.sendMessage(chatId, {
|
|
71
|
-
image: { url: card.image },
|
|
72
|
-
caption: cardText
|
|
73
|
-
});
|
|
74
|
-
} else {
|
|
75
|
-
// Text-only card
|
|
76
|
-
await this.client.socket.sendMessage(chatId, {
|
|
77
|
-
text: cardText
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Small delay between cards to prevent spam
|
|
82
|
-
if (i < cards.length - 1) {
|
|
83
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
+
// Send the carousel
|
|
87
|
+
const result = await this.client.socket.sendMessage(chatId, carouselMessage);
|
|
86
88
|
|
|
87
89
|
return {
|
|
88
90
|
success: true,
|
|
89
|
-
type: '
|
|
91
|
+
type: 'interactive_carousel',
|
|
90
92
|
cards: cards.length,
|
|
93
|
+
messageId: result.key.id,
|
|
91
94
|
mediaTypes: {
|
|
92
95
|
videos: cards.filter(c => c.video).length,
|
|
93
96
|
images: cards.filter(c => c.image).length,
|
|
@@ -96,14 +99,80 @@ export class UIComponents {
|
|
|
96
99
|
};
|
|
97
100
|
|
|
98
101
|
} catch (error) {
|
|
99
|
-
console.error('❌ Carousel
|
|
102
|
+
console.error('❌ Interactive Carousel failed, trying fallback:', error);
|
|
100
103
|
|
|
101
|
-
// Fallback
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
// Fallback 1: Try native carousel format
|
|
105
|
+
try {
|
|
106
|
+
const nativeCarousel = {
|
|
107
|
+
viewOnceMessage: {
|
|
108
|
+
message: {
|
|
109
|
+
messageContextInfo: {
|
|
110
|
+
deviceListMetadata: {},
|
|
111
|
+
deviceListMetadataVersion: 2
|
|
112
|
+
},
|
|
113
|
+
interactiveMessage: {
|
|
114
|
+
nativeFlowMessage: {
|
|
115
|
+
buttons: cards.map((card, i) => ({
|
|
116
|
+
name: 'single_select',
|
|
117
|
+
buttonParamsJson: JSON.stringify({
|
|
118
|
+
title: card.title,
|
|
119
|
+
sections: [{
|
|
120
|
+
title: card.subtitle || '',
|
|
121
|
+
rows: [{
|
|
122
|
+
title: card.title,
|
|
123
|
+
description: card.body,
|
|
124
|
+
id: `card_${i}`
|
|
125
|
+
}]
|
|
126
|
+
}]
|
|
127
|
+
})
|
|
128
|
+
}))
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const result = await this.client.socket.sendMessage(chatId, nativeCarousel);
|
|
136
|
+
return { success: true, type: 'native_carousel', cards: cards.length };
|
|
137
|
+
|
|
138
|
+
} catch (nativeError) {
|
|
139
|
+
console.error('❌ Native carousel also failed, using list fallback:', nativeError);
|
|
140
|
+
|
|
141
|
+
// Fallback 2: Use List Message (closest to carousel)
|
|
142
|
+
try {
|
|
143
|
+
const listMessage = {
|
|
144
|
+
text: options.title || 'Select an option',
|
|
145
|
+
footer: options.footer || `${cards.length} options available`,
|
|
146
|
+
title: options.title || 'Carousel',
|
|
147
|
+
buttonText: 'View Options',
|
|
148
|
+
sections: [{
|
|
149
|
+
title: 'All Options',
|
|
150
|
+
rows: cards.map((card, i) => ({
|
|
151
|
+
title: card.title,
|
|
152
|
+
description: card.body || card.subtitle || '',
|
|
153
|
+
rowId: `carousel_${i}`
|
|
154
|
+
}))
|
|
155
|
+
}]
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const result = await this.client.socket.sendMessage(chatId, listMessage);
|
|
159
|
+
return { success: true, type: 'list_fallback', cards: cards.length };
|
|
160
|
+
|
|
161
|
+
} catch (listError) {
|
|
162
|
+
console.error('❌ List fallback failed, using text:', listError);
|
|
163
|
+
|
|
164
|
+
// Fallback 3: Simple text with emojis
|
|
165
|
+
const fallbackText = `🎠 **${options.title || 'Carousel'}**\n\n` +
|
|
166
|
+
cards.map((card, i) =>
|
|
167
|
+
`${i + 1}️⃣ **${card.title}**\n` +
|
|
168
|
+
`${card.subtitle ? ` ${card.subtitle}\n` : ''}` +
|
|
169
|
+
` ${card.body || ''}\n`
|
|
170
|
+
).join('\n');
|
|
171
|
+
|
|
172
|
+
await this.client.socket.sendMessage(chatId, { text: fallbackText });
|
|
173
|
+
return { success: true, type: 'text_fallback', cards: cards.length };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
107
176
|
}
|
|
108
177
|
}
|
|
109
178
|
|