@isaxn/bailyes 1.0.0 → 2.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.
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+
3
+ const { getBaileys } = require("../core/baileys-loader.js");
4
+ const { BaseBuilder } = require("./base-builder.js");
5
+ const { relayInteractive } = require("./native-flow.js");
6
+
7
+ class Button extends BaseBuilder {
8
+ #client;
9
+
10
+ constructor(client) {
11
+ super();
12
+ if (!client) throw new Error("Socket is required");
13
+
14
+ this.#client = client;
15
+ this._buttons = [];
16
+ this._data = undefined;
17
+ this._currentSelectionIndex = -1;
18
+ this._currentSectionIndex = -1;
19
+ this._params = {};
20
+ }
21
+
22
+ setVideo(mediaPath, options = {}) {
23
+ if (!mediaPath) throw new Error("Url or buffer needed");
24
+ this._data = Buffer.isBuffer(mediaPath)
25
+ ? { video: mediaPath, ...options }
26
+ : { video: { url: mediaPath }, ...options };
27
+ return this;
28
+ }
29
+
30
+ setImage(mediaPath, options = {}) {
31
+ if (!mediaPath) throw new Error("Url or buffer needed");
32
+ this._data = Buffer.isBuffer(mediaPath)
33
+ ? { image: mediaPath, ...options }
34
+ : { image: { url: mediaPath }, ...options };
35
+ return this;
36
+ }
37
+
38
+ setDocument(mediaPath, options = {}) {
39
+ if (!mediaPath) throw new Error("Url or buffer needed");
40
+ this._data = Buffer.isBuffer(mediaPath)
41
+ ? { document: mediaPath, ...options }
42
+ : { document: { url: mediaPath }, ...options };
43
+ return this;
44
+ }
45
+
46
+ setMedia(obj) {
47
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
48
+ throw new TypeError("Media must be a plain object");
49
+ }
50
+ this._data = obj;
51
+ return this;
52
+ }
53
+
54
+ clearButtons() {
55
+ this._buttons = [];
56
+ return this;
57
+ }
58
+
59
+ setParams(obj) {
60
+ this._params = obj;
61
+ return this;
62
+ }
63
+
64
+ addButton(name, params) {
65
+ this._buttons.push({
66
+ name,
67
+ buttonParamsJson: typeof params === "string" ? params : JSON.stringify(params)
68
+ });
69
+ return this;
70
+ }
71
+
72
+ makeRow(header = "", title = "", description = "", id = "") {
73
+ if (this._currentSelectionIndex === -1 || this._currentSectionIndex === -1) {
74
+ throw new Error("You need to create a selection and a section first");
75
+ }
76
+
77
+ const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
78
+ buttonParams.sections[this._currentSectionIndex].rows.push({ header, title, description, id });
79
+ this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
80
+ return this;
81
+ }
82
+
83
+ makeSection(title = "", highlight_label = "") {
84
+ if (this._currentSelectionIndex === -1) {
85
+ throw new Error("You need to create a selection first");
86
+ }
87
+
88
+ const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
89
+ buttonParams.sections.push({ title, highlight_label, rows: [] });
90
+ this._currentSectionIndex = buttonParams.sections.length - 1;
91
+ this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
92
+ return this;
93
+ }
94
+
95
+ addSelection(title, options = {}) {
96
+ this._buttons.push({
97
+ ...options,
98
+ name: "single_select",
99
+ buttonParamsJson: JSON.stringify({ title, sections: [] })
100
+ });
101
+ this._currentSelectionIndex = this._buttons.length - 1;
102
+ this._currentSectionIndex = -1;
103
+ return this;
104
+ }
105
+
106
+ addReply(display_text = "", id = "", options = {}) {
107
+ this._buttons.push({
108
+ name: "quick_reply",
109
+ buttonParamsJson: JSON.stringify({ display_text, id, ...options })
110
+ });
111
+ return this;
112
+ }
113
+
114
+ addCall(display_text = "", id = "", options = {}) {
115
+ this._buttons.push({
116
+ name: "cta_call",
117
+ buttonParamsJson: JSON.stringify({ display_text, id, ...options })
118
+ });
119
+ return this;
120
+ }
121
+
122
+ addReminder(display_text = "", id = "", options = {}) {
123
+ this._buttons.push({
124
+ name: "cta_reminder",
125
+ buttonParamsJson: JSON.stringify({ display_text, id, ...options })
126
+ });
127
+ return this;
128
+ }
129
+
130
+ addCancelReminder(display_text = "", id = "", options = {}) {
131
+ this._buttons.push({
132
+ name: "cta_cancel_reminder",
133
+ buttonParamsJson: JSON.stringify({ display_text, id, ...options })
134
+ });
135
+ return this;
136
+ }
137
+
138
+ addAddress(display_text = "", id = "", options = {}) {
139
+ this._buttons.push({
140
+ name: "address_message",
141
+ buttonParamsJson: JSON.stringify({ display_text, id, ...options })
142
+ });
143
+ return this;
144
+ }
145
+
146
+ addLocation(options = {}) {
147
+ this._buttons.push({
148
+ name: "send_location",
149
+ buttonParamsJson: JSON.stringify(options)
150
+ });
151
+ return this;
152
+ }
153
+
154
+ addUrl(display_text = "", url = "", webview_interaction = false, options = {}) {
155
+ this._buttons.push({
156
+ ...options,
157
+ name: "cta_url",
158
+ buttonParamsJson: JSON.stringify({ display_text, url, webview_interaction, ...options })
159
+ });
160
+ return this;
161
+ }
162
+
163
+ addCopy(display_text = "", copy_code = "", options = {}) {
164
+ this._buttons.push({
165
+ name: "cta_copy",
166
+ buttonParamsJson: JSON.stringify({ display_text, copy_code, ...options })
167
+ });
168
+ return this;
169
+ }
170
+
171
+ async toCard() {
172
+ const { prepareWAMessageMedia } = await getBaileys();
173
+
174
+ let header = {
175
+ title: this._title,
176
+ subtitle: this._subtitle,
177
+ hasMediaAttachment: Boolean(this._data)
178
+ };
179
+
180
+ if (this._data) {
181
+ try {
182
+ const media = await prepareWAMessageMedia(this._data, { upload: this.#client.waUploadToServer });
183
+ header = { ...header, ...media };
184
+ } catch (error) {
185
+ if (!String(error).includes("Invalid media type")) throw error;
186
+ header = { ...header, ...this._data };
187
+ }
188
+ }
189
+
190
+ return {
191
+ body: { text: this._body },
192
+ footer: { text: this._footer },
193
+ header,
194
+ nativeFlowMessage: {
195
+ messageParamsJson: JSON.stringify(this._params),
196
+ buttons: this._buttons
197
+ }
198
+ };
199
+ }
200
+
201
+ async build(jid, options = {}) {
202
+ const { generateWAMessageFromContent } = await getBaileys();
203
+ const message = await this.toCard();
204
+
205
+ return generateWAMessageFromContent(
206
+ jid,
207
+ {
208
+ ...this._extraPayload,
209
+ interactiveMessage: { ...message, contextInfo: this._contextInfo }
210
+ },
211
+ { ...options }
212
+ );
213
+ }
214
+
215
+ async send(jid, options = {}) {
216
+ const msg = await this.build(jid, options);
217
+ return relayInteractive(this.#client, msg, options);
218
+ }
219
+ }
220
+
221
+ module.exports = { Button };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ const { getBaileys } = require("../core/baileys-loader.js");
4
+ const { BaseBuilder } = require("./base-builder.js");
5
+ const { relayInteractive } = require("./native-flow.js");
6
+
7
+ class Carousel extends BaseBuilder {
8
+ #client;
9
+
10
+ constructor(client) {
11
+ super();
12
+ if (!client) throw new Error("Socket is required");
13
+
14
+ this.#client = client;
15
+ this._cards = [];
16
+ }
17
+
18
+ addCard(card) {
19
+ const cards = Array.isArray(card) ? card : [card];
20
+ const baseIndex = this._cards.length;
21
+
22
+ for (const [index, c] of cards.entries()) {
23
+ if (!c?.header?.hasMediaAttachment) {
24
+ throw new Error(`Card [${baseIndex + index}] must include an image or video in header`);
25
+ }
26
+ }
27
+
28
+ this._cards.push(...cards);
29
+ return this;
30
+ }
31
+
32
+ async build(jid, options = {}) {
33
+ const { generateWAMessageFromContent } = await getBaileys();
34
+
35
+ return generateWAMessageFromContent(
36
+ jid,
37
+ {
38
+ ...this._extraPayload,
39
+ interactiveMessage: {
40
+ header: { hasMediaAttachment: false },
41
+ body: { text: this._body },
42
+ footer: { text: this._footer },
43
+ contextInfo: this._contextInfo,
44
+ carouselMessage: { cards: this._cards }
45
+ }
46
+ },
47
+ { ...options }
48
+ );
49
+ }
50
+
51
+ async send(jid, options = {}) {
52
+ const msg = await this.build(jid, options);
53
+ return relayInteractive(this.#client, msg, options);
54
+ }
55
+ }
56
+
57
+ module.exports = { Carousel };
@@ -0,0 +1,34 @@
1
+ /*
2
+ @author : isank dev
3
+ @linkch : https://whatsapp.com/channel/0029Vb8Fj4S1iUxiJPyKFh1U
4
+ @note : informasi update nya lewat ch
5
+ @tanggal : now
6
+ */
7
+
8
+ "use strict";
9
+
10
+ const { Toolkit } = require("./toolkit.js");
11
+ const { Button } = require("./button.js");
12
+ const { ButtonV2 } = require("./button-v2.js");
13
+ const { Carousel } = require("./carousel.js");
14
+ const { AIRich } = require("./ai-rich.js");
15
+ const { bind, sendLinkPreview } = require("./link-preview.js");
16
+ const { sendLivePhoto } = require("./live-photo.js");
17
+ const { sendLiveThumbnail } = require("./live-thumbnail.js");
18
+ const { bx } = require("./quick.js");
19
+
20
+ const VERSION = "2.1.0";
21
+
22
+ module.exports = {
23
+ VERSION,
24
+ Button,
25
+ ButtonV2,
26
+ Carousel,
27
+ AIRich,
28
+ Toolkit,
29
+ bind,
30
+ sendLinkPreview,
31
+ sendLivePhoto,
32
+ sendLiveThumbnail,
33
+ bx
34
+ };
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+
3
+ function createInlineEntity(type, ie) {
4
+ if (type === "hyperlink") {
5
+ return {
6
+ key: ie.key,
7
+ metadata: {
8
+ display_name: ie.text,
9
+ is_trusted: ie.is_trusted,
10
+ url: ie.url,
11
+ __typename: "GenAIInlineLinkItem"
12
+ }
13
+ };
14
+ }
15
+
16
+ if (type === "citation") {
17
+ return {
18
+ key: ie.key,
19
+ metadata: {
20
+ reference_id: ie.reference_id,
21
+ reference_url: ie.url,
22
+ reference_title: ie.url,
23
+ reference_display_name: ie.url,
24
+ sources: [],
25
+ __typename: "GenAISearchCitationItem"
26
+ }
27
+ };
28
+ }
29
+
30
+ if (type === "latex") {
31
+ return {
32
+ key: ie.key,
33
+ metadata: {
34
+ latex_expression: ie.text,
35
+ latex_image: {
36
+ url: ie.url,
37
+ width: Number(ie.width) || 100,
38
+ height: Number(ie.height) || 100
39
+ },
40
+ font_height: Number(ie.font_height) || 83.333333333333,
41
+ padding: Number(ie.padding) || 15,
42
+ __typename: "GenAILatexItem"
43
+ }
44
+ };
45
+ }
46
+
47
+ return null;
48
+ }
49
+
50
+ function extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
51
+ if (!extract) {
52
+ return { text, ie: [], inline_entities: [] };
53
+ }
54
+
55
+ const ie = [];
56
+ const inline_entities = [];
57
+
58
+ let result = "";
59
+ let last = 0;
60
+ let citationIndex = 1;
61
+ let hyperlinkIndex = 0;
62
+ let latexIndex = 0;
63
+ const stack = [];
64
+
65
+ for (let i = 0; i < text.length; i++) {
66
+ if (text[i] === "[" && text[i - 1] !== "\\") {
67
+ stack.push(i);
68
+ continue;
69
+ }
70
+
71
+ if (text[i] === "]" && (text[i + 1] === "(" || text[i + 1] === "<")) {
72
+ const start = stack.pop();
73
+ if (start == null) continue;
74
+
75
+ const open = text[i + 1];
76
+ const close = open === "(" ? ")" : ">";
77
+ const type = open === "(" ? "link" : "latex";
78
+
79
+ let end = i + 2;
80
+ let depth = 1;
81
+
82
+ while (end < text.length && depth) {
83
+ if (text[end] === open && text[end - 1] !== "\\") depth++;
84
+ else if (text[end] === close && text[end - 1] !== "\\") depth--;
85
+ end++;
86
+ }
87
+
88
+ if (depth) continue;
89
+
90
+ const raw = text.slice(start + 1, i).trim();
91
+ const url = text.slice(i + 2, end - 1).trim();
92
+
93
+ let key;
94
+ let tag;
95
+ let data;
96
+
97
+ if (type === "latex") {
98
+ if (!latex) continue;
99
+
100
+ const [txt = "", width = null, height = null, fontHeight = null, padding = null] = raw.split("|");
101
+
102
+ key = `NIXEL_LATEX_${latexIndex++}`;
103
+ tag = `{{${key}}}${txt || "image"}{{/${key}}}`;
104
+
105
+ data = {
106
+ type: "latex",
107
+ ie: { key, text: txt, url, width, height, font_height: fontHeight, padding }
108
+ };
109
+ } else if (raw) {
110
+ if (!hyperlink) continue;
111
+
112
+ const trusted = !url.startsWith("!");
113
+ const cleanUrl = trusted ? url : url.slice(1);
114
+
115
+ key = `NIXEL_HYPERLINK_${hyperlinkIndex++}`;
116
+ tag = `{{${key}}}${cleanUrl}{{/${key}}}`;
117
+
118
+ data = {
119
+ type: "hyperlink",
120
+ ie: { key, text: raw, url: cleanUrl, is_trusted: trusted }
121
+ };
122
+ } else {
123
+ if (!citation) continue;
124
+
125
+ key = `NIXEL_CITATION_${citationIndex - 1}`;
126
+ tag = `{{${key}}}${url}{{/${key}}}`;
127
+
128
+ data = {
129
+ type: "citation",
130
+ ie: { reference_id: citationIndex++, key, text: "", url }
131
+ };
132
+ }
133
+
134
+ result += text.slice(last, start) + tag;
135
+ last = end;
136
+
137
+ ie.push(data);
138
+
139
+ const entity = createInlineEntity(data.type, data.ie);
140
+ if (entity) inline_entities.push(entity);
141
+
142
+ i = end - 1;
143
+ }
144
+ }
145
+
146
+ result += text.slice(last);
147
+
148
+ return { text: result, ie, inline_entities };
149
+ }
150
+
151
+ async function waitAllPromises(input) {
152
+ const isPromise = (v) => v && typeof v.then === "function";
153
+ const isObject = (v) => v && typeof v === "object";
154
+
155
+ const deep = async (v) => {
156
+ if (isPromise(v)) return deep(await v);
157
+ if (Array.isArray(v)) return Promise.all(v.map(deep));
158
+ if (isObject(v)) {
159
+ const entries = await Promise.all(Object.entries(v).map(async ([k, val]) => [k, await deep(val)]));
160
+ return Object.fromEntries(entries);
161
+ }
162
+ return v;
163
+ };
164
+
165
+ return deep(await input);
166
+ }
167
+
168
+ module.exports = { extractIE, waitAllPromises };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ const { getBaileys } = require("../core/baileys-loader.js");
4
+
5
+ async function sendLinkPreview(client, jid, { text = "", link = "", title = "", description = "", thumbnail, options = {} } = {}) {
6
+ if (!client) throw new Error("Socket is required");
7
+ if (typeof jid !== "string") throw new TypeError("jid is not string");
8
+ if (typeof text !== "string") throw new TypeError("text is not string");
9
+ if (typeof link !== "string") throw new TypeError("link is not string");
10
+ if (typeof title !== "string") throw new TypeError("title is not string");
11
+ if (description && typeof description !== "string") throw new TypeError("description is not string");
12
+ if (thumbnail && !Buffer.isBuffer(thumbnail) && typeof thumbnail.url !== "string") {
13
+ throw new TypeError("thumbnail must be Buffer or object with url key");
14
+ }
15
+
16
+ const { prepareWAMessageMedia } = await getBaileys();
17
+
18
+ const image = thumbnail
19
+ ? await prepareWAMessageMedia(
20
+ { image: thumbnail },
21
+ { upload: client.waUploadToServer, mediaTypeOverride: "thumbnail-link" }
22
+ ).then((v) => v.imageMessage)
23
+ : undefined;
24
+
25
+ const finalText = link && !text.includes(link) ? `${link}\n${text}` : text;
26
+
27
+ return client.sendMessage(
28
+ jid,
29
+ {
30
+ text: finalText,
31
+ linkPreview: {
32
+ "matched-text": link,
33
+ title,
34
+ description,
35
+ jpegThumbnail: image?.jpegThumbnail,
36
+ highQualityThumbnail: image
37
+ }
38
+ },
39
+ options
40
+ );
41
+ }
42
+
43
+ function bind(client) {
44
+ if (!client) throw new Error("Socket is required");
45
+
46
+ Object.defineProperty(client, "sendLinkPreview", {
47
+ configurable: true,
48
+ writable: true,
49
+ value: (jid, text, link, title, description, thumbnail, options = {}) =>
50
+ sendLinkPreview(client, jid, { text, link, title, description, thumbnail, options })
51
+ });
52
+
53
+ return client;
54
+ }
55
+
56
+ module.exports = { bind, sendLinkPreview };
@@ -0,0 +1,59 @@
1
+ /*
2
+ @author : isank dev
3
+ @linkch : https://whatsapp.com/channel/0029Vb8Fj4S1iUxiJPyKFh1U
4
+ @note : informasi update nya lewat ch
5
+ @tanggal : now
6
+ */
7
+
8
+ "use strict";
9
+
10
+ const { getBaileys } = require("../core/baileys-loader.js");
11
+
12
+ async function sendLivePhoto(client, jid, { image, video, options = {} } = {}) {
13
+ if (!client) throw new Error("Socket is required");
14
+ if (!image) throw new Error("image is required");
15
+ if (!video) throw new Error("video is required");
16
+
17
+ const { prepareWAMessageMedia, generateWAMessageFromContent } = await getBaileys();
18
+
19
+ const preparedImage = await prepareWAMessageMedia(
20
+ { image: Buffer.isBuffer(image) ? image : { url: image } },
21
+ { upload: client.waUploadToServer }
22
+ );
23
+
24
+ const preparedVideo = await prepareWAMessageMedia(
25
+ { video: Buffer.isBuffer(video) ? video : { url: video } },
26
+ { upload: client.waUploadToServer }
27
+ );
28
+
29
+ const msg = generateWAMessageFromContent(
30
+ jid,
31
+ {
32
+ imageMessage: {
33
+ ...preparedImage.imageMessage,
34
+ contextInfo: { pairedMediaType: 5, statusSourceType: 0, ...options.contextInfo }
35
+ }
36
+ },
37
+ {}
38
+ );
39
+
40
+ await client.relayMessage(jid, msg.message, { messageId: msg.key.id });
41
+
42
+ await client.relayMessage(
43
+ jid,
44
+ {
45
+ videoMessage: {
46
+ ...preparedVideo.videoMessage,
47
+ contextInfo: { pairedMediaType: 6, statusSourceType: 0 }
48
+ },
49
+ messageContextInfo: {
50
+ messageAssociation: { associationType: 12, parentMessageKey: msg.key }
51
+ }
52
+ },
53
+ {}
54
+ );
55
+
56
+ return msg;
57
+ }
58
+
59
+ module.exports = { sendLivePhoto };
@@ -0,0 +1,56 @@
1
+ /*
2
+ @author : isank dev
3
+ @linkch : https://whatsapp.com/channel/0029Vb8Fj4S1iUxiJPyKFh1U
4
+ @note : informasi update nya lewat ch
5
+ @tanggal : now
6
+ */
7
+
8
+ "use strict";
9
+
10
+ const { getBaileys } = require("../core/baileys-loader.js");
11
+ const { Toolkit } = require("./toolkit.js");
12
+
13
+ async function sendLiveThumbnail(
14
+ client,
15
+ jid,
16
+ {
17
+ key,
18
+ text = "",
19
+ link = "",
20
+ title = "",
21
+ description = "",
22
+ images = [],
23
+ size = 300,
24
+ interval = 1500,
25
+ loops = 1,
26
+ quality = "highQualityThumbnail"
27
+ } = {}
28
+ ) {
29
+ if (!client) throw new Error("Socket is required");
30
+ if (!key) throw new Error("key is required, get it from client.sendMessage() result");
31
+ if (!Array.isArray(images) || !images.length) throw new Error("images must be a non-empty array");
32
+
33
+ const { delay } = await getBaileys();
34
+
35
+ const finalText = link && !text.includes(link) ? `${link}\n${text}` : text;
36
+
37
+ const thumbs = await Promise.all(
38
+ images.map(async (image) => Toolkit.resize(await Toolkit.fetchBuffer(image), size, size))
39
+ );
40
+
41
+ for (let loop = 0; loop < loops; loop++) {
42
+ for (const jpegThumbnail of thumbs) {
43
+ const linkPreview =
44
+ quality === "highQualityThumbnail"
45
+ ? { "matched-text": link, title, description, jpegThumbnail, highQualityThumbnail: { jpegThumbnail } }
46
+ : { "matched-text": link, title, description, jpegThumbnail };
47
+
48
+ await client.sendMessage(jid, { edit: key, text: finalText, linkPreview });
49
+ await delay(interval);
50
+ }
51
+ }
52
+
53
+ return key;
54
+ }
55
+
56
+ module.exports = { sendLiveThumbnail };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ function nativeFlowNodes() {
4
+ return [
5
+ {
6
+ tag: "biz",
7
+ attrs: {},
8
+ content: [
9
+ {
10
+ tag: "interactive",
11
+ attrs: { type: "native_flow", v: "1" },
12
+ content: [{ tag: "native_flow", attrs: { v: "9", name: "mixed" } }]
13
+ }
14
+ ]
15
+ }
16
+ ];
17
+ }
18
+
19
+ async function relayInteractive(client, msg, options = {}) {
20
+ await client.relayMessage(msg.key.remoteJid, msg.message, {
21
+ messageId: msg.key.id,
22
+ additionalNodes: nativeFlowNodes(),
23
+ ...options
24
+ });
25
+ return msg;
26
+ }
27
+
28
+ module.exports = { nativeFlowNodes, relayInteractive };