@prototypevip/baileys 0.1.4 → 0.1.5
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/HELPERS.md +107 -0
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/messages-media.js +6 -3
- package/lib/Utils/messages.js +1 -0
- package/lib/Utils/newsletter-status.js +2 -1
- package/lib/Utils/prototype-helpers.js +610 -0
- package/package.json +11 -4
package/HELPERS.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# @prototypevip/baileys — Helpers (v0.1.5)
|
|
2
|
+
|
|
3
|
+
طبقة helpers فوق المسارات الأصلية في المكتبة (`sock.sendMessage` → `nativeFlow` / `album` / `code` / `event` / `product`).
|
|
4
|
+
مفيش بروتوكول جديد هنا؛ كل دالة بتفوّض لمسار موجود ومجرَّب.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import makeWASocket, { attachPrototypeHelpers } from '@prototypevip/baileys'
|
|
10
|
+
|
|
11
|
+
const sock = makeWASocket({ ... })
|
|
12
|
+
attachPrototypeHelpers(sock)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
الدوال متاحة كمان كـ named exports: `sendButtons(sock, jid, content, options)` … إلخ.
|
|
16
|
+
|
|
17
|
+
## أزرار / قوائم
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
await sock.sendButtons(jid, {
|
|
21
|
+
text: 'اختار', footer: 'Prototype VIP',
|
|
22
|
+
buttons: [
|
|
23
|
+
{ text: 'Menu', id: '#menu' },
|
|
24
|
+
{ text: 'موقع', url: 'https://example.com' },
|
|
25
|
+
{ text: 'نسخ', copy: 'CODE' },
|
|
26
|
+
{ text: 'اتصل', call: '201234567890' }
|
|
27
|
+
]
|
|
28
|
+
}, { quoted: m })
|
|
29
|
+
|
|
30
|
+
// مع ميديا (بتتحوّل لـ header): image | video | document
|
|
31
|
+
await sock.sendButtons(jid, { text: 'كابشن', image: { url: '...' }, buttons: [...] })
|
|
32
|
+
|
|
33
|
+
// أيقونة AI (شات خاص فقط — في الجروب بتتجاهل)
|
|
34
|
+
await sock.sendAIMessage(jid, { text: 'أهلا', buttons: [...] })
|
|
35
|
+
|
|
36
|
+
// قائمة اختيار (single_select داخل Native Flow). legacy: true = listMessage الكلاسيكي
|
|
37
|
+
await sock.sendList(jid, {
|
|
38
|
+
text: 'القائمة', title: 'T', buttonText: 'افتح',
|
|
39
|
+
sections: [{ title: 'قسم', rows: [{ title: 'A', description: 'd', id: '#a' }] }]
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
await sock.sendQuickButtons(jid, 'اختار', ['نعم', 'لا'])
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## ألبوم / Carousel
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
await sock.sendAlbum(jid, [{ image: { url } , caption: '1' }, { video: { url } }], { delayMs: 1500 })
|
|
49
|
+
|
|
50
|
+
// Carousel حقيقي (كل كارت لازم image أو video)
|
|
51
|
+
await sock.sendCarousel(jid, {
|
|
52
|
+
text: 'منتجات', footer: 'Prototype VIP',
|
|
53
|
+
cards: [{ title: 'منتج 1', body: 'وصف', image: 'https://...', buttons: [{ text: 'اشتري', id: '#buy1' }] }]
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Rich (شكل Meta AI)
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
await sock.sendRichCode(jid, { title: 'مثال', code: 'console.log(1)', language: 'javascript' })
|
|
61
|
+
|
|
62
|
+
// ⚠️ HTML: مفيش render حقيقي لـ HTML جوه الفقاعة في المكتبة.
|
|
63
|
+
// sendRichHtml بيبعت الـ HTML كـ code block ملوّن داخل Rich Response.
|
|
64
|
+
await sock.sendRichHtml(jid, { title: 'Card', html: '<div>...</div>' })
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## مكالمات
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
// Scheduled Call Event (مفيش WebRTC outbound حقيقي في Baileys)
|
|
71
|
+
await sock.sendScheduledCall(jid, { name: 'اجتماع', startDate: new Date(Date.now() + 3600_000), callType: 'audio' })
|
|
72
|
+
await sock.sendCallInvite(jid, { name: 'مكالمة سريعة', callType: 'video', minutesFromNow: 2 })
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## متفرقات
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
await sock.sendViewOnce(jid, { image: { url }, caption: 'مرة واحدة' })
|
|
79
|
+
await sock.sendPoll(jid, 'رأيك؟', ['حلو', 'عادي'], { selectableCount: 1 })
|
|
80
|
+
await sock.sendReaction(jid, m.key, '🔥')
|
|
81
|
+
await sock.sendMentionAll(groupJid, 'يا جماعة')
|
|
82
|
+
await sock.sendLocation(jid, 30.04, 31.23, { name: 'القاهرة', address: '...' })
|
|
83
|
+
await sock.sendContact(jid, { fullName: 'أحمد', phone: '201234567890' })
|
|
84
|
+
await sock.sendProduct(jid, { title: 'منتج', price: 100, currencyCode: 'EGP', image: 'https://...' }) // الصورة مطلوبة
|
|
85
|
+
await sock.sendSticker(jid, { url: 'https://.../x.webp' })
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## JID / LID
|
|
89
|
+
|
|
90
|
+
الـ LID **مش** مشتق من رقم التليفون، فالتحويل بيعتمد على mapping حقيقي (`sock.signalRepository.lidMapping`)
|
|
91
|
+
وبيرجّع `null` لو الـ mapping مش معروف.
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
await sock.toLid('2010xxxxxxx@s.whatsapp.net') // → '...@lid' | null (async)
|
|
95
|
+
await sock.toPn('...@lid') // → '...@s.whatsapp.net' | null (async)
|
|
96
|
+
sock.normalizeJid('201...:12@s.whatsapp.net') // يشيل رقم الجهاز بس
|
|
97
|
+
sock.isLid(jid); sock.isPn(jid)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Builders
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
const btn = sock.button() // Button
|
|
104
|
+
const car = sock.carouselBuilder()
|
|
105
|
+
const rich = sock.aiRich()
|
|
106
|
+
// chain methods ثم .send(jid)
|
|
107
|
+
```
|
package/lib/Utils/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
DEFAULT_ORIGIN,
|
|
18
18
|
MEDIA_HKDF_KEY_MAPPING,
|
|
19
19
|
MEDIA_PATH_MAP,
|
|
20
|
+
NEWSLETTER_MEDIA_PATH_MAP,
|
|
20
21
|
} from "../Defaults/index.js";
|
|
21
22
|
import {
|
|
22
23
|
getBinaryNodeChild,
|
|
@@ -725,7 +726,7 @@ export const getWAUploadToServer = (
|
|
|
725
726
|
{ customUploadHosts, fetchAgent, logger, options },
|
|
726
727
|
refreshMediaConn,
|
|
727
728
|
) => {
|
|
728
|
-
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
|
729
|
+
return async (filePath, { mediaType, fileEncSha256B64, timeoutMs, newsletter }) => {
|
|
729
730
|
// send a query JSON to obtain the url & auth token to upload our media
|
|
730
731
|
let uploadInfo = await refreshMediaConn(false);
|
|
731
732
|
let urls;
|
|
@@ -745,7 +746,8 @@ export const getWAUploadToServer = (
|
|
|
745
746
|
for (const { hostname } of hosts) {
|
|
746
747
|
logger.debug(`uploading to "${hostname}"`);
|
|
747
748
|
const auth = encodeURIComponent(uploadInfo.auth);
|
|
748
|
-
const
|
|
749
|
+
const mediaPath = (newsletter && NEWSLETTER_MEDIA_PATH_MAP[mediaType]) || MEDIA_PATH_MAP[mediaType];
|
|
750
|
+
const url = `https://${hostname}${mediaPath}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`;
|
|
749
751
|
let result;
|
|
750
752
|
try {
|
|
751
753
|
result = await uploadMedia(
|
|
@@ -758,8 +760,9 @@ export const getWAUploadToServer = (
|
|
|
758
760
|
},
|
|
759
761
|
logger,
|
|
760
762
|
);
|
|
761
|
-
if (result?.url || result?.direct_path) {
|
|
763
|
+
if (result?.url || result?.direct_path || (newsletter && result?.handle)) {
|
|
762
764
|
urls = {
|
|
765
|
+
handle: result.handle,
|
|
763
766
|
mediaUrl: result.url,
|
|
764
767
|
directPath: result.direct_path,
|
|
765
768
|
meta_hmac: result.meta_hmac,
|
package/lib/Utils/messages.js
CHANGED
|
@@ -402,6 +402,7 @@ export const prepareWAMessageMedia = async (message, options) => {
|
|
|
402
402
|
fileEncSha256B64: fileSha256B64,
|
|
403
403
|
mediaType: mediaType,
|
|
404
404
|
timeoutMs: options.mediaUploadTimeoutMs,
|
|
405
|
+
newsletter: true,
|
|
405
406
|
});
|
|
406
407
|
await fs.unlink(filePath);
|
|
407
408
|
const obj = WAProto.Message.fromObject({
|
|
@@ -381,6 +381,7 @@ export const makeNewsletterStatusSender = (sock, config) => async (jid, content,
|
|
|
381
381
|
resolveServerId,
|
|
382
382
|
serverIdTimeoutMs,
|
|
383
383
|
transport,
|
|
384
|
+
wrapAdminProfile,
|
|
384
385
|
...messageOptions
|
|
385
386
|
} = options
|
|
386
387
|
|
|
@@ -424,7 +425,7 @@ export const makeNewsletterStatusSender = (sock, config) => async (jid, content,
|
|
|
424
425
|
|
|
425
426
|
const node = buildNewsletterStatusNode({
|
|
426
427
|
jid,
|
|
427
|
-
message: fullMsg.message,
|
|
428
|
+
message: wrapAdminProfile ? buildNewsletterAdminProfileStatusMessage(fullMsg.message) : fullMsg.message,
|
|
428
429
|
messageId: fullMsg.key.id,
|
|
429
430
|
mediaType,
|
|
430
431
|
mediaHandle: requestedMediaHandle ?? mediaId ?? uploadedMediaHandle,
|
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prototype VIP Baileys Helpers (0.1.5)
|
|
3
|
+
*
|
|
4
|
+
* طبقة helpers سهلة فوق المسارات الأصلية الموجودة في المكتبة
|
|
5
|
+
* (sock.sendMessage → nativeFlow / album / code / event / product ...).
|
|
6
|
+
* مفيش هنا أي بروتوكول جديد: كل دالة بتفوّض لمسار مجرَّب جوه المكتبة.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { proto } from "../../WAProto/index.js";
|
|
10
|
+
import { generateWAMessageFromContent } from "./messages.js";
|
|
11
|
+
// الكلاسات دي مصدَّرة أصلاً من message-builder.js عن طريق Utils/index.js
|
|
12
|
+
import { Button, ButtonV2, Carousel, AIRich, Toolkit } from "./message-builder.js";
|
|
13
|
+
|
|
14
|
+
/* ───────────────────────────── internals ───────────────────────────── */
|
|
15
|
+
|
|
16
|
+
const MEDIA_KEYS = ["image", "video", "document"];
|
|
17
|
+
|
|
18
|
+
const hasMedia = (obj) => MEDIA_KEYS.some((k) => obj?.[k]);
|
|
19
|
+
|
|
20
|
+
const isPrivateJid = (jid) =>
|
|
21
|
+
typeof jid === "string" && (jid.endsWith("@s.whatsapp.net") || jid.endsWith("@lid"));
|
|
22
|
+
|
|
23
|
+
const assertSock = (sock, method = "sendMessage") => {
|
|
24
|
+
if (!sock || typeof sock[method] !== "function") {
|
|
25
|
+
throw new Error(`Invalid socket: sock.${method} is not a function`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const defaultRowId = (label) => `#${String(label || "row").trim().replace(/\s+/g, "_")}`;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* يحوّل أي شكل مدعوم لزر إلى الصيغة اللي بتفهمها المكتبة في { nativeFlow: [...] }:
|
|
33
|
+
* { text, id } | { text, url } | { text, copy } | { text, call } | { text, sections }
|
|
34
|
+
* ويقبل كمان الصيغ البديلة: rowId / display_text / cta_url / copy_code / phone_number
|
|
35
|
+
* والصيغة الخام { name, buttonParamsJson } بتعدّي زي ما هي.
|
|
36
|
+
*/
|
|
37
|
+
function normalizeButton(btn) {
|
|
38
|
+
if (!btn || typeof btn !== "object") {
|
|
39
|
+
throw new TypeError("Each button must be an object");
|
|
40
|
+
}
|
|
41
|
+
if (btn.name && btn.buttonParamsJson) return btn; // native format
|
|
42
|
+
|
|
43
|
+
const text = btn.text ?? btn.display_text ?? btn.buttonText ?? btn.title;
|
|
44
|
+
const out = { text };
|
|
45
|
+
if (btn.icon) out.icon = btn.icon;
|
|
46
|
+
|
|
47
|
+
const id = btn.id ?? btn.rowId;
|
|
48
|
+
const url = btn.url ?? btn.cta_url;
|
|
49
|
+
const copy = btn.copy ?? btn.copy_code;
|
|
50
|
+
const call = btn.call ?? btn.phone_number;
|
|
51
|
+
|
|
52
|
+
if (id) out.id = id;
|
|
53
|
+
else if (copy) out.copy = String(copy);
|
|
54
|
+
else if (url) {
|
|
55
|
+
out.url = url;
|
|
56
|
+
if (btn.useWebview) out.useWebview = btn.useWebview;
|
|
57
|
+
} else if (call) out.call = String(call);
|
|
58
|
+
else if (Array.isArray(btn.sections)) out.sections = btn.sections;
|
|
59
|
+
else out.id = defaultRowId(text || "btn"); // default: quick_reply
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ───────────────────────────── buttons ───────────────────────────── */
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* يبني أزرار Native Flow بالصيغة الخام ({ name, buttonParamsJson })
|
|
67
|
+
* لو عاوز تبعتها مباشرة في interactiveMessage.nativeFlowMessage.buttons.
|
|
68
|
+
*/
|
|
69
|
+
export function buildNativeFlowButtons(buttons = []) {
|
|
70
|
+
return buttons.map((raw) => {
|
|
71
|
+
const btn = normalizeButton(raw);
|
|
72
|
+
if (btn.name && btn.buttonParamsJson) return btn;
|
|
73
|
+
const label = btn.text;
|
|
74
|
+
if (btn.id) {
|
|
75
|
+
return { name: "quick_reply", buttonParamsJson: JSON.stringify({ display_text: label || "Button", id: btn.id }) };
|
|
76
|
+
}
|
|
77
|
+
if (btn.copy) {
|
|
78
|
+
return { name: "cta_copy", buttonParamsJson: JSON.stringify({ display_text: label || "Copy", copy_code: btn.copy }) };
|
|
79
|
+
}
|
|
80
|
+
if (btn.url) {
|
|
81
|
+
return {
|
|
82
|
+
name: "cta_url",
|
|
83
|
+
buttonParamsJson: JSON.stringify({ display_text: label || "Open", url: btn.url, merchant_url: btn.url }),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (btn.call) {
|
|
87
|
+
return { name: "cta_call", buttonParamsJson: JSON.stringify({ display_text: label || "Call", phone_number: btn.call }) };
|
|
88
|
+
}
|
|
89
|
+
return { name: "single_select", buttonParamsJson: JSON.stringify({ title: label || "Select", sections: btn.sections }) };
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* أزرار Native Flow (تفوّض لـ sock.sendMessage → { nativeFlow })
|
|
95
|
+
*
|
|
96
|
+
* await sendButtons(sock, jid, {
|
|
97
|
+
* text: "اختار", footer: "Prototype VIP",
|
|
98
|
+
* buttons: [{ text:"Menu", id:"#menu" }, { text:"Site", url:"https://..." },
|
|
99
|
+
* { text:"Copy", copy:"CODE" }, { text:"Call", call:"2012..." }],
|
|
100
|
+
* // اختياري: image | video | document (بيتحوّل لـ header)، title، subtitle، ai: true
|
|
101
|
+
* }, { quoted: m })
|
|
102
|
+
*/
|
|
103
|
+
export async function sendButtons(sock, jid, content = {}, options = {}) {
|
|
104
|
+
assertSock(sock);
|
|
105
|
+
const { text, caption, buttons, ai, ...rest } = content;
|
|
106
|
+
|
|
107
|
+
if (!Array.isArray(buttons) || buttons.length === 0) {
|
|
108
|
+
throw new Error("sendButtons requires a non-empty buttons array");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const payload = { ...rest, nativeFlow: buttons.map(normalizeButton) };
|
|
112
|
+
|
|
113
|
+
// مسار nativeFlow في المكتبة بيستخدم text للنص العادي و caption مع الميديا
|
|
114
|
+
if (hasMedia(rest)) {
|
|
115
|
+
payload.caption = caption ?? text ?? "";
|
|
116
|
+
} else {
|
|
117
|
+
payload.text = text ?? caption ?? "";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// أيقونة الـ AI: sendMessage بيقبلها كـ content.ai وفي الشات الخاص بس
|
|
121
|
+
const wantAi = ai ?? options.ai ?? options.AI;
|
|
122
|
+
if (wantAi && isPrivateJid(jid)) payload.ai = true;
|
|
123
|
+
|
|
124
|
+
const { ai: _a, AI: _b, ...sendOptions } = options;
|
|
125
|
+
return sock.sendMessage(jid, payload, sendOptions);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* قائمة اختيار. الافتراضي: single_select داخل Native Flow (بيشتغل على الأجهزة الحديثة).
|
|
130
|
+
* مرّر legacy: true لو عاوز listMessage الكلاسيكي.
|
|
131
|
+
*/
|
|
132
|
+
export async function sendList(sock, jid, content = {}, options = {}) {
|
|
133
|
+
assertSock(sock);
|
|
134
|
+
const { text = "", footer, title = "", buttonText = "Select", sections, legacy = false, ...rest } = content;
|
|
135
|
+
|
|
136
|
+
if (!Array.isArray(sections) || sections.length === 0) {
|
|
137
|
+
throw new Error("sendList requires a non-empty sections array");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (legacy) {
|
|
141
|
+
const msg = generateWAMessageFromContent(
|
|
142
|
+
jid,
|
|
143
|
+
{
|
|
144
|
+
listMessage: {
|
|
145
|
+
title,
|
|
146
|
+
description: text,
|
|
147
|
+
buttonText,
|
|
148
|
+
listType: proto.Message.ListMessage.ListType.SINGLE_SELECT,
|
|
149
|
+
footerText: footer || undefined,
|
|
150
|
+
sections: sections.map((sec) => ({
|
|
151
|
+
title: sec.title || "",
|
|
152
|
+
rows: (sec.rows || []).map((row) => ({
|
|
153
|
+
title: row.title || row.text || "",
|
|
154
|
+
description: row.description || "",
|
|
155
|
+
rowId: row.rowId || row.id || defaultRowId(row.title || row.text),
|
|
156
|
+
})),
|
|
157
|
+
})),
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{ userJid: sock.user?.id, quoted: options.quoted, messageId: options.messageId }
|
|
161
|
+
);
|
|
162
|
+
const additionalNodes = isPrivateJid(jid)
|
|
163
|
+
? [{ tag: "biz", attrs: {}, content: [{ tag: "list", attrs: { v: "2", type: "product_list" } }] }]
|
|
164
|
+
: [];
|
|
165
|
+
await sock.relayMessage(jid, msg.message, {
|
|
166
|
+
messageId: msg.key.id,
|
|
167
|
+
additionalNodes: [...(options.additionalNodes || []), ...additionalNodes],
|
|
168
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
169
|
+
statusJidList: options.statusJidList,
|
|
170
|
+
});
|
|
171
|
+
return msg;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const nfSections = sections.map((sec) => ({
|
|
175
|
+
title: sec.title || "",
|
|
176
|
+
...(sec.highlight_label ? { highlight_label: sec.highlight_label } : {}),
|
|
177
|
+
rows: (sec.rows || []).map((row) => ({
|
|
178
|
+
header: row.header || "",
|
|
179
|
+
title: row.title || row.text || "",
|
|
180
|
+
description: row.description || "",
|
|
181
|
+
id: row.id || row.rowId || defaultRowId(row.title || row.text),
|
|
182
|
+
})),
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
return sendButtons(
|
|
186
|
+
sock,
|
|
187
|
+
jid,
|
|
188
|
+
{ ...rest, text, footer, title, buttons: [{ text: buttonText, sections: nfSections }] },
|
|
189
|
+
options
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** اختصار: أزرار رد سريع من نصوص بس */
|
|
194
|
+
export async function sendQuickButtons(sock, jid, text, buttonLabels = [], options = {}) {
|
|
195
|
+
const buttons = buttonLabels.map((label, i) => ({
|
|
196
|
+
text: label,
|
|
197
|
+
id: `#btn_${i + 1}`,
|
|
198
|
+
}));
|
|
199
|
+
return sendButtons(sock, jid, { text, buttons }, options);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** رسالة بأيقونة AI (شات خاص فقط — في الجروبات بتتبعت عادي من غير الأيقونة) */
|
|
203
|
+
export async function sendAIMessage(sock, jid, content, options = {}) {
|
|
204
|
+
const base = typeof content === "string" ? { text: content } : { ...content };
|
|
205
|
+
if (Array.isArray(base.buttons) && base.buttons.length) {
|
|
206
|
+
return sendButtons(sock, jid, { ...base, ai: true }, options);
|
|
207
|
+
}
|
|
208
|
+
assertSock(sock);
|
|
209
|
+
const { ai: _a, AI: _b, ...sendOptions } = options;
|
|
210
|
+
return sock.sendMessage(jid, isPrivateJid(jid) ? { ...base, ai: true } : base, sendOptions);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* ───────────────────────────── album ───────────────────────────── */
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* ألبوم صور/فيديوهات. المكتبة بتتوقع album كمصفوفة، وبتقرأ expectedImageCount/
|
|
217
|
+
* expectedVideoCount من نفس المصفوفة، فبنضيفهم عليها.
|
|
218
|
+
*
|
|
219
|
+
* await sendAlbum(sock, jid, [{ image:{url}, caption:"1" }, { video:{url} }], { quoted: m, delayMs: 1500 })
|
|
220
|
+
*/
|
|
221
|
+
export async function sendAlbum(sock, jid, mediaItems = [], options = {}) {
|
|
222
|
+
assertSock(sock);
|
|
223
|
+
if (!Array.isArray(mediaItems) || mediaItems.length === 0) {
|
|
224
|
+
throw new Error("sendAlbum requires a non-empty array of media items");
|
|
225
|
+
}
|
|
226
|
+
for (const [i, item] of mediaItems.entries()) {
|
|
227
|
+
if (!item || (!item.image && !item.video)) {
|
|
228
|
+
throw new Error(`sendAlbum: item [${i}] must contain image or video`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const album = Object.assign([...mediaItems], {
|
|
232
|
+
expectedImageCount: mediaItems.filter((i) => i.image).length,
|
|
233
|
+
expectedVideoCount: mediaItems.filter((i) => i.video).length,
|
|
234
|
+
});
|
|
235
|
+
return sock.sendMessage(jid, { album }, options);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* ───────────────────────────── carousel ───────────────────────────── */
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Carousel حقيقي عن طريق كلاسات المكتبة (Button.toCard + Carousel).
|
|
242
|
+
* كل كارت لازم يكون له image أو video.
|
|
243
|
+
*
|
|
244
|
+
* await sendCarousel(sock, jid, {
|
|
245
|
+
* text: "اختار منتج", footer: "Prototype VIP",
|
|
246
|
+
* cards: [{ title:"منتج 1", body:"وصف", image:"https://..." (أو Buffer), buttons:[{ text:"اشتري", id:"#buy1" }] }]
|
|
247
|
+
* })
|
|
248
|
+
*/
|
|
249
|
+
export async function sendCarousel(sock, jid, content = {}, options = {}) {
|
|
250
|
+
assertSock(sock, "relayMessage");
|
|
251
|
+
const { text = "", footer = "", cards } = content;
|
|
252
|
+
if (!Array.isArray(cards) || cards.length === 0) {
|
|
253
|
+
throw new Error("sendCarousel requires a non-empty cards array");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const carousel = new Carousel(sock).setBody(text);
|
|
257
|
+
if (footer) carousel.setFooter(footer);
|
|
258
|
+
|
|
259
|
+
for (const [i, card] of cards.entries()) {
|
|
260
|
+
const media = card.image ?? card.video;
|
|
261
|
+
if (!media) throw new Error(`sendCarousel: card [${i}] must include image or video`);
|
|
262
|
+
|
|
263
|
+
const b = new Button(sock);
|
|
264
|
+
if (card.title) b.setTitle(card.title);
|
|
265
|
+
if (card.subtitle) b.setSubtitle(card.subtitle);
|
|
266
|
+
b.setBody(card.body || card.caption || card.title || " ");
|
|
267
|
+
if (card.footer) b.setFooter(card.footer);
|
|
268
|
+
|
|
269
|
+
const toData = (m, kind) => (Buffer.isBuffer(m) ? { [kind]: m } : typeof m === "string" ? { [kind]: { url: m } } : { [kind]: m });
|
|
270
|
+
b.setMedia(card.image ? toData(card.image, "image") : toData(card.video, "video"));
|
|
271
|
+
|
|
272
|
+
for (const nb of buildNativeFlowButtons(card.buttons || [])) {
|
|
273
|
+
b.addButton(nb.name, nb.buttonParamsJson);
|
|
274
|
+
}
|
|
275
|
+
carousel.addCard(await b.toCard());
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
await carousel.send(jid, { userJid: sock.user?.id, ...options });
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* ───────────────────────────── rich (AI) ───────────────────────────── */
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* ⚠️ مهم: واتساب/المكتبة مفيهاش render حقيقي لـ HTML داخل الفقاعة.
|
|
285
|
+
* اللي بيحصل فعلياً: بتتبعت رسالة Rich Response (شكل Meta AI) والـ HTML
|
|
286
|
+
* بيظهر كـ code block ملوّن (syntax highlight) — ده المسار الوحيد المدعوم
|
|
287
|
+
* والمجرَّب في المكتبة (prepareRichResponseMessage).
|
|
288
|
+
*/
|
|
289
|
+
export async function sendRichHtml(sock, jid, content, options = {}) {
|
|
290
|
+
assertSock(sock);
|
|
291
|
+
const { title, html = "", summary, footer } = typeof content === "string" ? { html: content } : content || {};
|
|
292
|
+
if (!html) throw new Error("sendRichHtml requires html");
|
|
293
|
+
|
|
294
|
+
return sock.sendMessage(
|
|
295
|
+
jid,
|
|
296
|
+
{
|
|
297
|
+
...(title ? { headerText: title } : {}),
|
|
298
|
+
...(summary ? { contentText: summary } : {}),
|
|
299
|
+
code: html,
|
|
300
|
+
language: "html",
|
|
301
|
+
...(footer ? { footerText: footer } : {}),
|
|
302
|
+
},
|
|
303
|
+
options
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** alias قديم — نفس sendRichHtml (اتشال منه المسار الوهمي AIRich.html) */
|
|
308
|
+
export async function sendRichHtmlAdvanced(sock, jid, content, options = {}) {
|
|
309
|
+
return sendRichHtml(sock, jid, content, options);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** رسالة Rich بكود ملوّن بأي لغة */
|
|
313
|
+
export async function sendRichCode(sock, jid, { code, language = "javascript", title, summary, footer } = {}, options = {}) {
|
|
314
|
+
assertSock(sock);
|
|
315
|
+
if (!code) throw new Error("sendRichCode requires code");
|
|
316
|
+
return sock.sendMessage(
|
|
317
|
+
jid,
|
|
318
|
+
{
|
|
319
|
+
...(title ? { headerText: title } : {}),
|
|
320
|
+
...(summary ? { contentText: summary } : {}),
|
|
321
|
+
code,
|
|
322
|
+
language,
|
|
323
|
+
...(footer ? { footerText: footer } : {}),
|
|
324
|
+
},
|
|
325
|
+
options
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* ───────────────────────────── misc senders ───────────────────────────── */
|
|
330
|
+
|
|
331
|
+
export async function sendViewOnce(sock, jid, content, options = {}) {
|
|
332
|
+
assertSock(sock);
|
|
333
|
+
const payload = typeof content === "string" ? { text: content } : { ...content };
|
|
334
|
+
return sock.sendMessage(jid, { ...payload, viewOnce: true }, options);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function sendReaction(sock, jid, key, emoji = "👍") {
|
|
338
|
+
assertSock(sock);
|
|
339
|
+
return sock.sendMessage(jid, { react: { text: emoji, key } });
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export async function sendPoll(sock, jid, name, values = [], options = {}) {
|
|
343
|
+
assertSock(sock);
|
|
344
|
+
const { selectableCount = 1, ...sendOptions } = options;
|
|
345
|
+
return sock.sendMessage(jid, { poll: { name, values, selectableCount } }, sendOptions);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** منشن لكل أعضاء الجروب (بيرمي خطأ لو معرفش يجيب الأعضاء بدل ما يبعت من غير منشن) */
|
|
349
|
+
export async function sendMentionAll(sock, jid, text, options = {}) {
|
|
350
|
+
assertSock(sock);
|
|
351
|
+
if (!jid.endsWith("@g.us")) throw new Error("sendMentionAll only works in groups");
|
|
352
|
+
const meta = await sock.groupMetadata(jid);
|
|
353
|
+
const mentions = (meta.participants || []).map((p) => p.id).filter(Boolean);
|
|
354
|
+
return sock.sendMessage(jid, { text, mentions }, options);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** options: { name, address, ...sendOptions } */
|
|
358
|
+
export async function sendLocation(sock, jid, degreesLatitude, degreesLongitude, options = {}) {
|
|
359
|
+
assertSock(sock);
|
|
360
|
+
const { name = "", address = "", ...sendOptions } = options;
|
|
361
|
+
return sock.sendMessage(
|
|
362
|
+
jid,
|
|
363
|
+
{ location: { degreesLatitude, degreesLongitude, name, address } },
|
|
364
|
+
sendOptions
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** contacts: { fullName|name, phone|number, organization|org } أو مصفوفة منهم */
|
|
369
|
+
export async function sendContact(sock, jid, contacts, options = {}) {
|
|
370
|
+
assertSock(sock);
|
|
371
|
+
const clean = (s) => String(s ?? "").replace(/[\r\n;,\\]/g, " ").trim();
|
|
372
|
+
const list = (Array.isArray(contacts) ? contacts : [contacts]).map((c) => {
|
|
373
|
+
const phone = String(c.phone || c.number || "").replace(/\D/g, "");
|
|
374
|
+
if (!phone) throw new Error("sendContact: phone is required");
|
|
375
|
+
const name = clean(c.fullName || c.name || phone);
|
|
376
|
+
const org = clean(c.organization || c.org);
|
|
377
|
+
const vcard =
|
|
378
|
+
`BEGIN:VCARD\nVERSION:3.0\nFN:${name}\n` +
|
|
379
|
+
(org ? `ORG:${org}\n` : "") +
|
|
380
|
+
`TEL;type=CELL;type=VOICE;waid=${phone}:+${phone}\nEND:VCARD`;
|
|
381
|
+
return { displayName: name, vcard };
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
return sock.sendMessage(
|
|
385
|
+
jid,
|
|
386
|
+
{
|
|
387
|
+
contacts: {
|
|
388
|
+
displayName: list.length === 1 ? list[0].displayName : `${list.length} contacts`,
|
|
389
|
+
contacts: list,
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
options
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** product: { title, description, price, currencyCode, productId, retailerId, url, image|thumbnail } (الصورة مطلوبة) */
|
|
397
|
+
export async function sendProduct(sock, jid, product = {}, options = {}) {
|
|
398
|
+
assertSock(sock);
|
|
399
|
+
const productImage = product.image || product.thumbnail || product.productImage;
|
|
400
|
+
if (!productImage) throw new Error("sendProduct requires an image (image | thumbnail | productImage)");
|
|
401
|
+
const image = typeof productImage === "string" ? { url: productImage } : productImage;
|
|
402
|
+
|
|
403
|
+
return sock.sendMessage(
|
|
404
|
+
jid,
|
|
405
|
+
{
|
|
406
|
+
product: {
|
|
407
|
+
productId: String(product.productId || "1"),
|
|
408
|
+
title: product.title || "Product",
|
|
409
|
+
description: product.description || "",
|
|
410
|
+
currencyCode: product.currencyCode || "USD",
|
|
411
|
+
priceAmount1000: product.price ? Math.round(Number(product.price) * 1000) : 0,
|
|
412
|
+
retailerId: product.retailerId || "prototypevip",
|
|
413
|
+
url: product.url || "",
|
|
414
|
+
productImageCount: 1,
|
|
415
|
+
productImage: image,
|
|
416
|
+
},
|
|
417
|
+
businessOwnerJid: product.businessOwnerJid || sock.user?.id,
|
|
418
|
+
body: product.body || product.description || "",
|
|
419
|
+
footer: product.footer || "",
|
|
420
|
+
},
|
|
421
|
+
options
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** sticker: Buffer | { url } | رابط/مسار نصي */
|
|
426
|
+
export async function sendSticker(sock, jid, sticker, options = {}) {
|
|
427
|
+
assertSock(sock);
|
|
428
|
+
const media = typeof sticker === "string" ? { url: sticker } : sticker;
|
|
429
|
+
return sock.sendMessage(jid, { sticker: media }, options);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/* ───────────────────────────── calls ───────────────────────────── */
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* مكالمة مجدولة (Event بنوع call). مفيش outbound WebRTC call حقيقي في Baileys.
|
|
436
|
+
* callType: "audio" | "video"
|
|
437
|
+
*/
|
|
438
|
+
export async function sendScheduledCall(sock, jid, content = {}, options = {}) {
|
|
439
|
+
assertSock(sock);
|
|
440
|
+
const {
|
|
441
|
+
name = "Call",
|
|
442
|
+
description = "",
|
|
443
|
+
startDate = new Date(Date.now() + 5 * 60 * 1000),
|
|
444
|
+
endDate,
|
|
445
|
+
callType = "audio",
|
|
446
|
+
extraGuestsAllowed = true,
|
|
447
|
+
location,
|
|
448
|
+
} = content;
|
|
449
|
+
|
|
450
|
+
const toDate = (d) => (d instanceof Date ? d : new Date(d));
|
|
451
|
+
const start = toDate(startDate);
|
|
452
|
+
if (Number.isNaN(start.getTime())) throw new Error("sendScheduledCall: invalid startDate");
|
|
453
|
+
const end = endDate ? toDate(endDate) : new Date(start.getTime() + 60 * 60 * 1000);
|
|
454
|
+
if (Number.isNaN(end.getTime())) throw new Error("sendScheduledCall: invalid endDate");
|
|
455
|
+
|
|
456
|
+
return sock.sendMessage(
|
|
457
|
+
jid,
|
|
458
|
+
{
|
|
459
|
+
event: {
|
|
460
|
+
name,
|
|
461
|
+
description,
|
|
462
|
+
startDate: start,
|
|
463
|
+
endDate: end,
|
|
464
|
+
call: callType === "video" ? "video" : "audio",
|
|
465
|
+
isScheduleCall: true,
|
|
466
|
+
extraGuestsAllowed,
|
|
467
|
+
location,
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
options
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export async function sendCallInvite(sock, jid, content = {}, options = {}) {
|
|
475
|
+
const {
|
|
476
|
+
name = "مكالمة واردة",
|
|
477
|
+
description = "اضغط للانضمام للمكالمة",
|
|
478
|
+
callType = "audio",
|
|
479
|
+
minutesFromNow = 2,
|
|
480
|
+
} = typeof content === "string" ? { name: content } : content;
|
|
481
|
+
|
|
482
|
+
return sendScheduledCall(
|
|
483
|
+
sock,
|
|
484
|
+
jid,
|
|
485
|
+
{
|
|
486
|
+
name,
|
|
487
|
+
description,
|
|
488
|
+
startDate: new Date(Date.now() + minutesFromNow * 60 * 1000),
|
|
489
|
+
callType,
|
|
490
|
+
extraGuestsAllowed: true,
|
|
491
|
+
},
|
|
492
|
+
options
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/* ───────────────────────────── JID / LID ───────────────────────────── */
|
|
497
|
+
|
|
498
|
+
export function isLid(jid) {
|
|
499
|
+
return typeof jid === "string" && jid.endsWith("@lid");
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export function isPn(jid) {
|
|
503
|
+
return typeof jid === "string" && jid.endsWith("@s.whatsapp.net");
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const stripDevice = (jid) => {
|
|
507
|
+
if (typeof jid !== "string") return jid;
|
|
508
|
+
const [user, server] = jid.split("@");
|
|
509
|
+
return `${user.split(":")[0]}@${server}`;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* LID مش مشتق من رقم التليفون — لازم mapping حقيقي من WhatsApp.
|
|
514
|
+
* بتستعمل sock.signalRepository.lidMapping. بترجّع null لو الـ mapping مش معروف.
|
|
515
|
+
*/
|
|
516
|
+
export async function toLid(sock, jid) {
|
|
517
|
+
if (!jid) return jid;
|
|
518
|
+
if (isLid(jid)) return stripDevice(jid);
|
|
519
|
+
const lid = await sock?.signalRepository?.lidMapping?.getLIDForPN?.(stripDevice(jid));
|
|
520
|
+
return lid ? stripDevice(lid) : null;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
export async function toPn(sock, jid) {
|
|
524
|
+
if (!jid) return jid;
|
|
525
|
+
if (isPn(jid)) return stripDevice(jid);
|
|
526
|
+
const pn = await sock?.signalRepository?.lidMapping?.getPNForLID?.(stripDevice(jid));
|
|
527
|
+
return pn ? stripDevice(pn) : null;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/** يشيل رقم الجهاز (:12) من أي JID من غير ما يغيّر نوعه */
|
|
531
|
+
export function normalizeJid(jid) {
|
|
532
|
+
return stripDevice(jid);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/* ───────────────────────────── attach ───────────────────────────── */
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* يربط كل الـ helpers على sock:
|
|
539
|
+
* attachPrototypeHelpers(sock); await sock.sendButtons(jid, {...})
|
|
540
|
+
*/
|
|
541
|
+
export function attachPrototypeHelpers(sock) {
|
|
542
|
+
if (!sock || typeof sock.relayMessage !== "function" || typeof sock.sendMessage !== "function") {
|
|
543
|
+
throw new Error("Invalid socket instance");
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
sock.sendButtons = (jid, content, opts) => sendButtons(sock, jid, content, opts);
|
|
547
|
+
sock.sendList = (jid, content, opts) => sendList(sock, jid, content, opts);
|
|
548
|
+
sock.sendAlbum = (jid, media, opts) => sendAlbum(sock, jid, media, opts);
|
|
549
|
+
sock.sendRichHtml = (jid, content, opts) => sendRichHtml(sock, jid, content, opts);
|
|
550
|
+
sock.sendRichHtmlAdvanced = (jid, content, opts) => sendRichHtmlAdvanced(sock, jid, content, opts);
|
|
551
|
+
sock.sendRichCode = (jid, content, opts) => sendRichCode(sock, jid, content, opts);
|
|
552
|
+
sock.sendAIMessage = (jid, content, opts) => sendAIMessage(sock, jid, content, opts);
|
|
553
|
+
sock.sendQuickButtons = (jid, text, labels, opts) => sendQuickButtons(sock, jid, text, labels, opts);
|
|
554
|
+
sock.sendCarousel = (jid, content, opts) => sendCarousel(sock, jid, content, opts);
|
|
555
|
+
sock.sendViewOnce = (jid, content, opts) => sendViewOnce(sock, jid, content, opts);
|
|
556
|
+
sock.sendReaction = (jid, key, emoji) => sendReaction(sock, jid, key, emoji);
|
|
557
|
+
sock.sendPoll = (jid, name, values, opts) => sendPoll(sock, jid, name, values, opts);
|
|
558
|
+
sock.sendMentionAll = (jid, text, opts) => sendMentionAll(sock, jid, text, opts);
|
|
559
|
+
sock.sendLocation = (jid, lat, lng, opts) => sendLocation(sock, jid, lat, lng, opts);
|
|
560
|
+
sock.sendContact = (jid, contacts, opts) => sendContact(sock, jid, contacts, opts);
|
|
561
|
+
sock.sendProduct = (jid, product, opts) => sendProduct(sock, jid, product, opts);
|
|
562
|
+
sock.sendSticker = (jid, sticker, opts) => sendSticker(sock, jid, sticker, opts);
|
|
563
|
+
sock.sendScheduledCall = (jid, content, opts) => sendScheduledCall(sock, jid, content, opts);
|
|
564
|
+
sock.sendCallInvite = (jid, content, opts) => sendCallInvite(sock, jid, content, opts);
|
|
565
|
+
|
|
566
|
+
// JID / LID
|
|
567
|
+
sock.toLid = (jid) => toLid(sock, jid); // async
|
|
568
|
+
sock.toPn = (jid) => toPn(sock, jid); // async
|
|
569
|
+
sock.isLid = isLid;
|
|
570
|
+
sock.isPn = isPn;
|
|
571
|
+
sock.normalizeJid = normalizeJid;
|
|
572
|
+
|
|
573
|
+
// Builders (من message-builder.js)
|
|
574
|
+
sock.button = () => new Button(sock);
|
|
575
|
+
sock.buttonV2 = () => new ButtonV2(sock);
|
|
576
|
+
sock.carouselBuilder = () => new Carousel(sock);
|
|
577
|
+
sock.aiRich = () => new AIRich(sock);
|
|
578
|
+
sock.Toolkit = Toolkit;
|
|
579
|
+
|
|
580
|
+
return sock;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export default {
|
|
584
|
+
buildNativeFlowButtons,
|
|
585
|
+
sendButtons,
|
|
586
|
+
sendList,
|
|
587
|
+
sendAlbum,
|
|
588
|
+
sendRichHtml,
|
|
589
|
+
sendRichHtmlAdvanced,
|
|
590
|
+
sendRichCode,
|
|
591
|
+
sendAIMessage,
|
|
592
|
+
sendQuickButtons,
|
|
593
|
+
sendCarousel,
|
|
594
|
+
sendViewOnce,
|
|
595
|
+
sendReaction,
|
|
596
|
+
sendPoll,
|
|
597
|
+
sendMentionAll,
|
|
598
|
+
sendLocation,
|
|
599
|
+
sendContact,
|
|
600
|
+
sendProduct,
|
|
601
|
+
sendSticker,
|
|
602
|
+
sendScheduledCall,
|
|
603
|
+
sendCallInvite,
|
|
604
|
+
toLid,
|
|
605
|
+
toPn,
|
|
606
|
+
isLid,
|
|
607
|
+
isPn,
|
|
608
|
+
normalizeJid,
|
|
609
|
+
attachPrototypeHelpers,
|
|
610
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prototypevip/baileys",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Baileys fork (@prototypevip/baileys) — clean + Channel/Group/Personal Status
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Baileys fork (@prototypevip/baileys) — clean + Channel/Group/Personal Status + Interactive Buttons/Lists/Album/Carousel + Rich code responses + Call Invites helpers (0.1.5)",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"files": [
|
|
21
21
|
"lib/**/*",
|
|
22
22
|
"WAProto/**/*",
|
|
23
|
-
"engine-requirements.js"
|
|
23
|
+
"engine-requirements.js",
|
|
24
|
+
"HELPERS.md"
|
|
24
25
|
],
|
|
25
26
|
"keywords": [
|
|
26
27
|
"automation",
|
|
@@ -34,7 +35,13 @@
|
|
|
34
35
|
"whatsapp-bot",
|
|
35
36
|
"whatsapp-chat",
|
|
36
37
|
"whatsapp-group",
|
|
37
|
-
"whatsapp-web"
|
|
38
|
+
"whatsapp-web",
|
|
39
|
+
"interactive-messages",
|
|
40
|
+
"buttons",
|
|
41
|
+
"album",
|
|
42
|
+
"native-flow",
|
|
43
|
+
"call-invite",
|
|
44
|
+
"rich-response"
|
|
38
45
|
],
|
|
39
46
|
"homepage": "https://github.com/GSK-F/baileys",
|
|
40
47
|
"author": "The Prototype",
|