@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.
@@ -1,65 +1,117 @@
1
- import {
2
- downloadContentFromMessage
3
- } from "@whiskeysockets/baileys";
4
- import fs from "fs";
5
- import path from "path";
6
-
7
- export class Context {
8
- constructor(sock, msg) {
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { getBaileys } = require("./baileys-loader.js");
6
+
7
+ class Context {
8
+ constructor(sock, msg, { store = null } = {}) {
9
9
  this.sock = sock;
10
10
  this.msg = msg;
11
+ this.store = store;
11
12
 
12
13
  this.chat = msg.key.remoteJid;
13
- this.sender =
14
- msg.key.participant ||
15
- msg.participant ||
16
- msg.key.remoteJid;
14
+ this.sender = msg.key.participant || msg.participant || msg.key.remoteJid;
15
+ this.isGroup = Boolean(this.chat && this.chat.endsWith("@g.us"));
16
+ this.isLid = Boolean(this.sender && this.sender.endsWith("@lid"));
17
+ this.fromMe = Boolean(msg.key.fromMe);
17
18
 
18
- this.isGroup = this.chat.endsWith("@g.us");
19
19
  this.message = msg.message;
20
20
 
21
21
  this.text =
22
22
  this.message?.conversation ||
23
23
  this.message?.extendedTextMessage?.text ||
24
+ this.message?.imageMessage?.caption ||
25
+ this.message?.videoMessage?.caption ||
24
26
  "";
27
+
28
+ this.command = null;
29
+ this.args = [];
30
+ }
31
+
32
+ get isImage() {
33
+ return Boolean(this.message?.imageMessage);
34
+ }
35
+
36
+ get isVideo() {
37
+ return Boolean(this.message?.videoMessage);
38
+ }
39
+
40
+ get isAudio() {
41
+ return Boolean(this.message?.audioMessage);
42
+ }
43
+
44
+ get isSticker() {
45
+ return Boolean(this.message?.stickerMessage);
46
+ }
47
+
48
+ get isDocument() {
49
+ return Boolean(this.message?.documentMessage);
25
50
  }
26
51
 
27
- // ===== MEDIA =====
28
- get isImage() { return !!this.message?.imageMessage; }
29
- get isVideo() { return !!this.message?.videoMessage; }
30
- get isAudio() { return !!this.message?.audioMessage; }
31
52
  get isVN() {
32
- return this.isAudio && this.message.audioMessage?.ptt;
53
+ return this.isAudio && Boolean(this.message.audioMessage?.ptt);
54
+ }
55
+
56
+ getName(jid = this.sender) {
57
+ if (this.store) return this.store.getName(jid);
58
+ return String(jid || "").split("@")[0];
59
+ }
60
+
61
+ async getProfilePicture(jid = this.sender) {
62
+ if (!jid) return null;
63
+ try {
64
+ return await this.sock.profilePictureUrl(jid, "image");
65
+ } catch {
66
+ return null;
67
+ }
33
68
  }
34
69
 
35
70
  async downloadMedia(folder = "media") {
36
- let type, msg;
71
+ const { downloadContentFromMessage } = await getBaileys();
72
+
73
+ let type;
74
+ let target;
37
75
 
38
- if (this.isImage) type = "image", msg = this.message.imageMessage;
39
- else if (this.isVideo) type = "video", msg = this.message.videoMessage;
40
- else if (this.isAudio) type = "audio", msg = this.message.audioMessage;
41
- else return null;
76
+ if (this.isImage) {
77
+ type = "image";
78
+ target = this.message.imageMessage;
79
+ } else if (this.isVideo) {
80
+ type = "video";
81
+ target = this.message.videoMessage;
82
+ } else if (this.isAudio) {
83
+ type = "audio";
84
+ target = this.message.audioMessage;
85
+ } else if (this.isSticker) {
86
+ type = "sticker";
87
+ target = this.message.stickerMessage;
88
+ } else if (this.isDocument) {
89
+ type = "document";
90
+ target = this.message.documentMessage;
91
+ } else {
92
+ return null;
93
+ }
42
94
 
43
- const stream = await downloadContentFromMessage(msg, type);
44
- const buffer = [];
95
+ const stream = await downloadContentFromMessage(target, type);
96
+ const chunks = [];
45
97
 
46
- for await (const chunk of stream) buffer.push(chunk);
98
+ for await (const chunk of stream) chunks.push(chunk);
47
99
 
48
- if (!fs.existsSync(folder)) fs.mkdirSync(folder);
100
+ if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
49
101
 
50
- const ext = type === "image" ? "jpg" : type === "video" ? "mp4" : "mp3";
102
+ const extensions = { image: "jpg", video: "mp4", audio: "mp3", sticker: "webp", document: "bin" };
103
+ const ext = extensions[type] || "bin";
51
104
  const filePath = path.join(folder, `${Date.now()}.${ext}`);
52
105
 
53
- fs.writeFileSync(filePath, Buffer.concat(buffer));
106
+ fs.writeFileSync(filePath, Buffer.concat(chunks));
54
107
  return filePath;
55
108
  }
56
109
 
57
- // ===== SEND =====
58
- reply(text) {
59
- return this.sock.sendMessage(this.chat, { text }, { quoted: this.msg });
110
+ reply(text, options = {}) {
111
+ return this.sock.sendMessage(this.chat, { text }, { quoted: this.msg, ...options });
60
112
  }
61
113
 
62
- replyButtons(text, buttons, footer = "") {
114
+ replyButtons(text, buttons = [], footer = "", options = {}) {
63
115
  return this.sock.sendMessage(
64
116
  this.chat,
65
117
  {
@@ -72,7 +124,15 @@ export class Context {
72
124
  })),
73
125
  headerType: 1
74
126
  },
75
- { quoted: this.msg }
127
+ { quoted: this.msg, ...options }
76
128
  );
77
129
  }
78
- }
130
+
131
+ react(emoji) {
132
+ return this.sock.sendMessage(this.chat, {
133
+ react: { text: emoji, key: this.msg.key }
134
+ });
135
+ }
136
+ }
137
+
138
+ module.exports = { Context };
@@ -1,15 +1,27 @@
1
- export class Events {
1
+ "use strict";
2
+
3
+ class Events {
2
4
  constructor() {
3
5
  this.events = {};
4
6
  }
5
7
 
6
8
  on(event, fn) {
7
9
  (this.events[event] ||= []).push(fn);
10
+ return this;
11
+ }
12
+
13
+ off(event, fn) {
14
+ if (!this.events[event]) return this;
15
+ this.events[event] = this.events[event].filter((listener) => listener !== fn);
16
+ return this;
8
17
  }
9
18
 
10
19
  emit(event, data) {
11
20
  for (const fn of this.events[event] || []) {
12
21
  fn(data);
13
22
  }
23
+ return this;
14
24
  }
15
- }
25
+ }
26
+
27
+ module.exports = { Events };
@@ -1,40 +1,57 @@
1
- export class Handler {
2
- constructor(prefix = ["!","."]) {
3
- this.prefix = prefix;
1
+ "use strict";
2
+
3
+ class Handler {
4
+ constructor(prefix = ["!", "."]) {
5
+ this.prefix = Array.isArray(prefix) ? prefix : [prefix];
4
6
  this.commands = new Map();
5
7
  this.hears = [];
6
8
  }
7
9
 
8
10
  command(name, fn) {
9
- this.commands.set(name, fn);
11
+ const names = Array.isArray(name) ? name : [name];
12
+ for (const n of names) this.commands.set(n, fn);
13
+ return this;
10
14
  }
11
15
 
12
16
  hear(pattern, fn) {
13
17
  this.hears.push({ pattern, fn });
18
+ return this;
19
+ }
20
+
21
+ matchPrefix(text) {
22
+ for (const p of this.prefix) {
23
+ if (text.startsWith(p)) return p;
24
+ }
25
+ return null;
14
26
  }
15
27
 
16
- handle(ctx) {
17
- const text = ctx.text.trim();
28
+ async handle(ctx) {
29
+ const text = (ctx.text || "").trim();
18
30
  if (!text) return;
19
31
 
20
- for (const p of this.prefix) {
21
- if (text.startsWith(p)) {
22
- const [cmd, ...args] = text.slice(p.length).split(/\s+/);
23
- if (this.commands.has(cmd)) {
24
- ctx.command = cmd;
25
- ctx.args = args;
26
- return this.commands.get(cmd)(ctx);
27
- }
32
+ const prefix = this.matchPrefix(text);
33
+
34
+ if (prefix !== null) {
35
+ const [cmd, ...args] = text.slice(prefix.length).trim().split(/\s+/);
36
+ const key = (cmd || "").toLowerCase();
37
+
38
+ if (this.commands.has(key)) {
39
+ ctx.command = key;
40
+ ctx.args = args;
41
+ ctx.text = args.join(" ");
42
+ return this.commands.get(key)(ctx);
28
43
  }
29
44
  }
30
45
 
31
46
  for (const h of this.hears) {
32
- if (
33
- typeof h.pattern === "string" && text === h.pattern ||
34
- h.pattern instanceof RegExp && h.pattern.test(text)
35
- ) {
47
+ const isString = typeof h.pattern === "string" && text === h.pattern;
48
+ const isRegex = h.pattern instanceof RegExp && h.pattern.test(text);
49
+
50
+ if (isString || isRegex) {
36
51
  return h.fn(ctx);
37
52
  }
38
53
  }
39
54
  }
40
- }
55
+ }
56
+
57
+ module.exports = { Handler };
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+
5
+ class Store {
6
+ constructor(options = {}) {
7
+ this.contacts = new Map();
8
+ this.chats = new Map();
9
+ this.groupMetadata = new Map();
10
+ this.messages = new Map();
11
+ this.maxMessagesPerChat = options.maxMessagesPerChat || 100;
12
+ this.file = options.file || null;
13
+ this.autosaveInterval = options.autosaveInterval ?? 30000;
14
+ this._timer = null;
15
+ }
16
+
17
+ bind(ev) {
18
+ if (this.file) this.readFromFile(this.file);
19
+
20
+ ev.on("contacts.upsert", (contacts) => {
21
+ for (const contact of contacts || []) this.upsertContact(contact);
22
+ });
23
+
24
+ ev.on("contacts.update", (updates) => {
25
+ for (const update of updates || []) this.upsertContact(update);
26
+ });
27
+
28
+ ev.on("chats.upsert", (chats) => {
29
+ for (const chat of chats || []) this.upsertChat(chat);
30
+ });
31
+
32
+ ev.on("chats.update", (updates) => {
33
+ for (const update of updates || []) this.upsertChat(update);
34
+ });
35
+
36
+ ev.on("chats.delete", (ids) => {
37
+ for (const id of ids || []) this.chats.delete(id);
38
+ });
39
+
40
+ ev.on("messages.upsert", (payload) => {
41
+ for (const msg of payload?.messages || []) this.upsertMessage(msg);
42
+ });
43
+
44
+ ev.on("messages.update", (updates) => {
45
+ for (const update of updates || []) this.patchMessage(update);
46
+ });
47
+
48
+ ev.on("messages.delete", (item) => {
49
+ if (Array.isArray(item?.keys)) {
50
+ for (const key of item.keys) {
51
+ this.messages.get(key.remoteJid)?.delete(key.id);
52
+ }
53
+ return;
54
+ }
55
+ if (item?.jid) this.messages.delete(item.jid);
56
+ });
57
+
58
+ ev.on("groups.update", (updates) => {
59
+ for (const update of updates || []) this.upsertGroupMetadata(update);
60
+ });
61
+
62
+ ev.on("group-participants.update", (data) => this.applyParticipantsUpdate(data));
63
+
64
+ if (this.file && this.autosaveInterval > 0) {
65
+ this._timer = setInterval(() => this.writeToFile(this.file), this.autosaveInterval);
66
+ if (this._timer.unref) this._timer.unref();
67
+ }
68
+
69
+ return this;
70
+ }
71
+
72
+ upsertContact(contact) {
73
+ if (!contact?.id) return;
74
+ const existing = this.contacts.get(contact.id) || { id: contact.id };
75
+ this.contacts.set(contact.id, { ...existing, ...contact });
76
+ }
77
+
78
+ upsertChat(chat) {
79
+ if (!chat?.id) return;
80
+ const existing = this.chats.get(chat.id) || { id: chat.id };
81
+ this.chats.set(chat.id, { ...existing, ...chat });
82
+ }
83
+
84
+ upsertGroupMetadata(meta) {
85
+ if (!meta?.id) return;
86
+ const existing = this.groupMetadata.get(meta.id) || { id: meta.id };
87
+ this.groupMetadata.set(meta.id, { ...existing, ...meta });
88
+ }
89
+
90
+ applyParticipantsUpdate({ id, participants, action } = {}) {
91
+ const meta = this.groupMetadata.get(id);
92
+ if (!meta || !Array.isArray(meta.participants) || !Array.isArray(participants)) return;
93
+
94
+ if (action === "add" || action === "promote" || action === "demote") {
95
+ for (const jid of participants) {
96
+ if (!meta.participants.some((p) => p.id === jid)) {
97
+ meta.participants.push({ id: jid });
98
+ }
99
+ }
100
+ }
101
+
102
+ if (action === "remove") {
103
+ meta.participants = meta.participants.filter((p) => !participants.includes(p.id));
104
+ }
105
+ }
106
+
107
+ upsertMessage(msg) {
108
+ const jid = msg?.key?.remoteJid;
109
+ const id = msg?.key?.id;
110
+ if (!jid || !id) return;
111
+
112
+ let bucket = this.messages.get(jid);
113
+ if (!bucket) {
114
+ bucket = new Map();
115
+ this.messages.set(jid, bucket);
116
+ }
117
+
118
+ bucket.set(id, msg);
119
+
120
+ while (bucket.size > this.maxMessagesPerChat) {
121
+ bucket.delete(bucket.keys().next().value);
122
+ }
123
+ }
124
+
125
+ patchMessage(update) {
126
+ const jid = update?.key?.remoteJid;
127
+ const id = update?.key?.id;
128
+ if (!jid || !id) return;
129
+
130
+ const bucket = this.messages.get(jid);
131
+ const existing = bucket?.get(id);
132
+ if (existing) bucket.set(id, { ...existing, ...update.update });
133
+ }
134
+
135
+ loadMessage(jid, id) {
136
+ return this.messages.get(jid)?.get(id) || null;
137
+ }
138
+
139
+ getContact(jid) {
140
+ return this.contacts.get(jid) || null;
141
+ }
142
+
143
+ getChat(jid) {
144
+ return this.chats.get(jid) || null;
145
+ }
146
+
147
+ getGroupMetadata(jid) {
148
+ return this.groupMetadata.get(jid) || null;
149
+ }
150
+
151
+ getName(jid) {
152
+ if (!jid) return "";
153
+ const contact = this.contacts.get(jid);
154
+ const fallback = String(jid).split("@")[0];
155
+ return contact?.name || contact?.notify || contact?.verifiedName || fallback;
156
+ }
157
+
158
+ toJSON() {
159
+ return {
160
+ contacts: Array.from(this.contacts.values()),
161
+ chats: Array.from(this.chats.values()),
162
+ groupMetadata: Array.from(this.groupMetadata.values()),
163
+ messages: Array.from(this.messages.entries()).map(([jid, bucket]) => [
164
+ jid,
165
+ Array.from(bucket.values())
166
+ ])
167
+ };
168
+ }
169
+
170
+ fromJSON(data) {
171
+ if (!data) return;
172
+
173
+ this.contacts = new Map((data.contacts || []).map((c) => [c.id, c]));
174
+ this.chats = new Map((data.chats || []).map((c) => [c.id, c]));
175
+ this.groupMetadata = new Map((data.groupMetadata || []).map((g) => [g.id, g]));
176
+ this.messages = new Map(
177
+ (data.messages || []).map(([jid, msgs]) => [
178
+ jid,
179
+ new Map(msgs.map((m) => [m.key.id, m]))
180
+ ])
181
+ );
182
+ }
183
+
184
+ writeToFile(file = this.file) {
185
+ if (!file) return;
186
+ try {
187
+ fs.writeFileSync(file, JSON.stringify(this.toJSON()));
188
+ } catch {
189
+ return;
190
+ }
191
+ }
192
+
193
+ readFromFile(file = this.file) {
194
+ if (!file || !fs.existsSync(file)) return;
195
+ try {
196
+ const raw = fs.readFileSync(file, "utf-8");
197
+ this.fromJSON(JSON.parse(raw));
198
+ } catch {
199
+ return;
200
+ }
201
+ }
202
+
203
+ stop() {
204
+ if (this._timer) clearInterval(this._timer);
205
+ if (this.file) this.writeToFile(this.file);
206
+ }
207
+ }
208
+
209
+ module.exports = { Store };
package/src/index.js CHANGED
@@ -1,56 +1,134 @@
1
- //isanamd code dont delete
2
- export { WAClient } from "./core/client.js";
3
- import { Context } from "./core/context.js";
4
- import { Events } from "./core/events.js";
5
- import { Handler } from "./core/handler.js";
1
+ /*
2
+ @author : isank dev
3
+ @linkch : https://whatsapp.com/channel/0029Vb8Fj4S1iUxiJPyKFh1U
4
+ @note : informasi update nya lewat ch
5
+ @tanggal : now
6
+ */
6
7
 
7
- const cooldown = new Map();
8
+ "use strict";
8
9
 
9
- function canReply(jid, delay = 3000) {
10
- const now = Date.now();
11
- if (cooldown.has(jid) && now - cooldown.get(jid) < delay) {
12
- return false;
13
- }
14
- cooldown.set(jid, now);
15
- return true;
16
- }
10
+ const { WAClient } = require("./core/client.js");
11
+ const { Context } = require("./core/context.js");
12
+ const { Events } = require("./core/events.js");
13
+ const { Handler } = require("./core/handler.js");
14
+ const { Store } = require("./core/store.js");
15
+ const {
16
+ VERSION,
17
+ Button,
18
+ ButtonV2,
19
+ Carousel,
20
+ AIRich,
21
+ Toolkit,
22
+ bind,
23
+ sendLinkPreview,
24
+ sendLivePhoto,
25
+ sendLiveThumbnail,
26
+ bx
27
+ } = require("./message/index.js");
17
28
 
18
- export class Bailyes {
29
+ class Bailyes {
19
30
  constructor(options = {}) {
20
31
  this.auth = options.auth || "auth";
21
32
  this.prefix = options.prefix || ["!"];
22
- this.client = new WAClient();
33
+ this.cooldown = options.cooldown ?? 0;
34
+
35
+ this.client = new WAClient(options);
23
36
  this.events = new Events();
24
37
  this.handler = new Handler(this.prefix);
38
+
39
+ this._cooldownMap = new Map();
40
+ this.sock = null;
41
+ }
42
+
43
+ get store() {
44
+ return this.client.store;
25
45
  }
26
46
 
27
-
28
47
  on(event, fn) {
48
+ this.client.on(event, fn);
49
+ return this;
50
+ }
51
+
52
+ onFramework(event, fn) {
29
53
  this.events.on(event, fn);
54
+ return this;
30
55
  }
31
56
 
32
57
  command(name, fn) {
33
58
  this.handler.command(name, fn);
59
+ return this;
34
60
  }
35
61
 
36
62
  hear(pattern, fn) {
37
63
  this.handler.hear(pattern, fn);
64
+ return this;
65
+ }
66
+
67
+ _canReply(jid) {
68
+ if (!this.cooldown) return true;
69
+
70
+ const now = Date.now();
71
+ const last = this._cooldownMap.get(jid);
72
+
73
+ if (last && now - last < this.cooldown) return false;
74
+
75
+ this._cooldownMap.set(jid, now);
76
+ return true;
38
77
  }
39
78
 
40
79
  async start() {
41
- const sock = await this.client.connect(this.auth);
80
+ this.client.on("messages.upsert", ({ messages, type }) => {
81
+ if (type !== "notify") return;
42
82
 
43
- sock.ev.on("messages.upsert", ({ messages }) => {
44
83
  const msg = messages?.[0];
45
84
  if (!msg || !msg.message || msg.key.fromMe) return;
46
85
 
47
- const ctx = new Context(sock, msg);
86
+ const ctx = new Context(this.sock, msg, { store: this.store });
48
87
 
49
- if (!canReply(ctx.chat)) return;
88
+ if (!this._canReply(ctx.chat)) return;
50
89
 
51
90
  this.events.emit("message", ctx);
91
+ this.handler.handle(ctx).catch((error) => this.events.emit("error", error));
92
+ });
52
93
 
53
- this.handler.handle(ctx);
94
+ this.client.on("open", (sock) => {
95
+ this.sock = sock;
96
+ bind(sock);
97
+ this.events.emit("ready", sock);
54
98
  });
99
+
100
+ this.client.on("qr", (qr) => this.events.emit("qr", qr));
101
+ this.client.on("pairing-code", (code) => this.events.emit("pairing-code", code));
102
+ this.client.on("close", (info) => this.events.emit("close", info));
103
+ this.client.on("logged-out", () => this.events.emit("logged-out"));
104
+
105
+ this.sock = await this.client.connect();
106
+ bind(this.sock);
107
+
108
+ return this.sock;
109
+ }
110
+
111
+ stop() {
112
+ this.client.stop();
55
113
  }
56
- }
114
+ }
115
+
116
+ module.exports = {
117
+ Bailyes,
118
+ WAClient,
119
+ Context,
120
+ Events,
121
+ Handler,
122
+ Store,
123
+ VERSION,
124
+ Button,
125
+ ButtonV2,
126
+ Carousel,
127
+ AIRich,
128
+ Toolkit,
129
+ bind,
130
+ sendLinkPreview,
131
+ sendLivePhoto,
132
+ sendLiveThumbnail,
133
+ bx
134
+ };