beniocord.js 2.1.0 → 2.1.2

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/Client.js CHANGED
@@ -9,7 +9,10 @@ const Message = require("./structures/Message");
9
9
  const User = require("./structures/User");
10
10
  const Channel = require("./structures/Channel");
11
11
  const Emoji = require("./structures/Emoji");
12
+ const Sticker = require("./structures/Sticker");
13
+
12
14
  const { MessageEmbed, MessageAttachment } = require("./structures/Util");
15
+ const { formatUrl } = require("./helpers");
13
16
 
14
17
  let global = {
15
18
  token: "",
@@ -18,6 +21,23 @@ let global = {
18
21
 
19
22
  class Client extends EventEmitter {
20
23
  /**
24
+ * @typedef {Object} ClientEvents
25
+ * @property {User} ready - Fired when the client finishes connecting
26
+ * @property {Message} messageCreate - Fired when a new message is created
27
+ * @property {Message} messageUpdate - Fired when a message is updated
28
+ * @property {Message} messageDelete - Fired when a message is deleted
29
+ * @property {Channel} channelCreate - Fired when a new channel is created
30
+ * @property {Channel} channelDelete - Fired when a channel is deleted
31
+ * @property {Channel} channelUpdate - Fired when a channel is updated
32
+ * @property {{channel: Channel, member: User}} channelMemberAdd - Fired when a member joins a channel
33
+ * @property {{channel: Channel, member: User}} channelMemberRemove - Fired when a member leaves a channel
34
+ * @property {User} channelMemberUpdate - Fired when a member updates their info in a channel
35
+ * @property {Emoji} emojiCreate - Fired when a new emoji is created
36
+ * @property {Emoji} emojiDelete - Fired when an emoji is deleted
37
+ * @property {Error} error - Fired when an error occurs
38
+ * @property {void} disconnect - Fired when disconnected from the gateway
39
+ * @property {void} reconnect - Fired when reconnecting to the gateway
40
+ *
21
41
  * @fires Client#ready
22
42
  * @fires Client#messageCreate
23
43
  * @fires Client#messageDelete
@@ -38,12 +58,13 @@ class Client extends EventEmitter {
38
58
  * @fires Client#typingStart
39
59
  * @fires Client#typingStop
40
60
  * @class Client
41
- * @description Classe principal do BenioCord.js - Gerencia a comunicação com a API e eventos do bot
42
- * @param {Object} options - Opções de configuração do cliente
43
- * @param {string} options.token - Token do bot para autenticação
61
+ * @description The main class of BenioCord.js, responsible for managing API communication and bot events.
62
+ * @param {Object} options - Client configuration options
63
+ * @param {string} options.token - Bot token used for authentication
44
64
  * @example
45
- * const { Client } = require('beniocord.js');
46
- * const client = new Client({ token: 'YOUR_BOT_TOKEN' });
65
+ * const Beniocord = require('beniocord.js');
66
+ * const client = new Beniocord({ token: 'YOUR_BOT_TOKEN' });
67
+ * client.login();
47
68
  */
48
69
  constructor({ token }) {
49
70
  super();
@@ -61,6 +82,7 @@ class Client extends EventEmitter {
61
82
  this.isConnected = false;
62
83
  this.isReady = false;
63
84
  this.status = 'online';
85
+ this.version = require('./package.json').version;
64
86
 
65
87
  // Configuration options
66
88
  this.config = {
@@ -174,7 +196,8 @@ class Client extends EventEmitter {
174
196
  }
175
197
 
176
198
  /**
177
- * Disconnects the bot from the server
199
+ * Kills the connection to the server
200
+ * @returns {void}
178
201
  */
179
202
  disconnect() {
180
203
  this._stopHeartbeat();
@@ -213,10 +236,14 @@ class Client extends EventEmitter {
213
236
  /**
214
237
  * Sets the bot's status
215
238
  * @param {string} status - Status: "online", "away", "dnd", "offline"
239
+ * @returns {Promise<Object>}
240
+ * @example
241
+ * client.setStatus("dnd").then((data) => {
242
+ * console.log("Status updated:", data);
243
+ * });
216
244
  */
217
245
  async setStatus(status) {
218
246
  const validStatuses = ["online", "offline", "away", "dnd"];
219
-
220
247
  if (!validStatuses.includes(status)) {
221
248
  throw new ClientError(
222
249
  `Invalid status. Valid statuses are: ${validStatuses.join(", ")}`,
@@ -226,7 +253,14 @@ class Client extends EventEmitter {
226
253
 
227
254
  this._ensureConnected();
228
255
  this.status = status;
229
- this.socket.emit('status:update', { status });
256
+
257
+ return new Promise((resolve) => {
258
+ this.socket.once('user:status-update', (data) => {
259
+ resolve(data);
260
+ });
261
+
262
+ this.socket.emit('status:update', { status });
263
+ });
230
264
  }
231
265
 
232
266
  /**
@@ -424,7 +458,7 @@ class Client extends EventEmitter {
424
458
  * Adds a member to a channel
425
459
  * @param {string} channelId - Channel ID
426
460
  * @param {string} userId - User ID to add
427
- * @param {string} role - Member role (default: 'member')
461
+ * @param {string} [role] - Member role (default: 'member')
428
462
  * @returns {Promise<Object>} Response data
429
463
  */
430
464
  async addChannelMember(channelId, userId, role = 'member') {
@@ -584,31 +618,27 @@ class Client extends EventEmitter {
584
618
  * Edits a message
585
619
  * @param {string} messageId - Message ID
586
620
  * @param {string} newContent - New message content
587
- * @returns {Promise<Object>} Response data
621
+ * @returns {Promise<Message>} Response data
588
622
  */
589
623
  async editMessage(messageId, newContent) {
590
624
  return new Promise((resolve, reject) => {
591
- try {
592
- this._ensureConnected();
593
- } catch (error) {
594
- return reject(error);
595
- }
596
-
597
625
  this.socket.emit(
598
626
  'message:edit',
599
627
  { messageId, content: newContent },
600
- (response) => {
628
+ async (response) => {
601
629
  if (response && response.error) {
602
630
  reject(new ClientError(response.error, "EDIT_ERROR"));
603
631
  } else {
604
632
  this._updateMessageContent(messageId, newContent, new Date().toISOString());
605
- resolve(response);
633
+ const msg = await this._processSocketMessage(response); // transforma response em Message
634
+ resolve(msg);
606
635
  }
607
636
  }
608
637
  );
609
638
  });
610
639
  }
611
640
 
641
+
612
642
  /**
613
643
  * Deletes a message
614
644
  * @param {string} messageId - Message ID
@@ -680,9 +710,54 @@ class Client extends EventEmitter {
680
710
  async fetchMessage(channelId, messageId) {
681
711
  try {
682
712
  const res = await this._axios.get(`/api/channels/${channelId}/messages/${messageId}`);
683
- return new Message(res.data, this);
713
+ const raw = res.data;
714
+
715
+ // --- USER ---
716
+ const userData = {
717
+ id: raw.user_id,
718
+ username: raw.username,
719
+ display_name: raw.display_name,
720
+ avatar_url: raw.avatar_url,
721
+ status: raw.status || 'online',
722
+ emblems: raw.emblems || [],
723
+ is_bot: raw.is_bot ?? false,
724
+ last_seen: raw.last_seen ?? raw.created_at,
725
+ created_at: raw.created_at,
726
+ };
727
+ const messageData = { ...raw, user: userData };
728
+ const message = new Message(messageData, this);
729
+ if (message.author) this.cache.users.set(message.author.id, message.author);
730
+
731
+ // --- CHANNEL ---
732
+ if (!message.channel && raw.channel_id) {
733
+ // Tenta pegar da cache
734
+ let channel = this.cache.channels.get(raw.channel_id);
735
+ if (!channel) {
736
+ channel = await this.fetchChannel(raw.channel_id);
737
+ }
738
+ message.channel = channel;
739
+ }
740
+
741
+ // --- STICKER ---
742
+ if (!message.sticker && raw.sticker_id) {
743
+ let sticker = this.cache.stickers.get(raw.sticker_id);
744
+
745
+ if (!sticker) {
746
+ try {
747
+ sticker = await this.fetchSticker(raw.sticker_id);
748
+ } catch (_) {
749
+ sticker = null;
750
+ }
751
+ }
752
+
753
+ message.sticker = sticker;
754
+ }
755
+
756
+ return message;
684
757
  } catch (error) {
685
- throw error instanceof ClientError ? error : new ClientError(error.message, "FETCH_MESSAGE_ERROR");
758
+ throw error instanceof ClientError
759
+ ? error
760
+ : new ClientError(error.message, "FETCH_MESSAGE_ERROR");
686
761
  }
687
762
  }
688
763
 
@@ -693,6 +768,7 @@ class Client extends EventEmitter {
693
768
  /**
694
769
  * Starts typing indicator in a channel
695
770
  * @param {string} channelId - Channel ID
771
+ * @returns {void}
696
772
  */
697
773
  startTyping(channelId) {
698
774
  try {
@@ -706,6 +782,7 @@ class Client extends EventEmitter {
706
782
  /**
707
783
  * Stops typing indicator in a channel
708
784
  * @param {string} channelId - Channel ID
785
+ * @returns {void}
709
786
  */
710
787
  stopTyping(channelId) {
711
788
  try {
@@ -746,13 +823,12 @@ class Client extends EventEmitter {
746
823
  /**
747
824
  * Fetches all available emojis
748
825
  * @param {Object} options - Fetch options
749
- * @param {boolean} options.includeOthers - Include emojis from other users
750
826
  * @param {string} options.search - Search query
751
827
  * @returns {Promise<Emoji[]>} Array of emoji objects
752
828
  */
753
829
  async fetchAllEmojis(options = {}) {
754
830
  try {
755
- const endpoint = options.includeOthers ? '/api/emojis/all' : '/api/emojis';
831
+ const endpoint = '/api/emojis/all';
756
832
  const params = {};
757
833
 
758
834
  if (options.search) {
@@ -760,7 +836,9 @@ class Client extends EventEmitter {
760
836
  }
761
837
 
762
838
  const res = await this._axios.get(endpoint, { params });
839
+
763
840
  const emojis = res.data.map(e => {
841
+ if (!e.user_id) e.user_id = this.user.id;
764
842
  const emoji = new Emoji(e);
765
843
  this.cache.emojis.set(emoji.id, emoji);
766
844
  return emoji;
@@ -768,7 +846,9 @@ class Client extends EventEmitter {
768
846
 
769
847
  return emojis;
770
848
  } catch (error) {
771
- throw error instanceof ClientError ? error : new ClientError(error.message, "FETCH_EMOJIS_ERROR");
849
+ throw error instanceof ClientError
850
+ ? error
851
+ : new ClientError(error.message, "FETCH_EMOJIS_ERROR");
772
852
  }
773
853
  }
774
854
 
@@ -785,8 +865,9 @@ class Client extends EventEmitter {
785
865
 
786
866
  try {
787
867
  const res = await this._axios.get(`/api/stickers/${id}`);
788
- this.cache.stickers.set(res.data.id, res.data);
789
- return res.data;
868
+ const sticker = new Sticker(res.data);
869
+ this.cache.stickers.set(sticker.id, sticker);
870
+ return sticker;
790
871
  } catch (error) {
791
872
  throw error instanceof ClientError
792
873
  ? error
@@ -849,6 +930,7 @@ class Client extends EventEmitter {
849
930
 
850
931
  /**
851
932
  * Clears all cached data
933
+ * @returns {void}
852
934
  */
853
935
  clearCache() {
854
936
  this.cache.users.clear();
@@ -945,7 +1027,7 @@ class Client extends EventEmitter {
945
1027
  });
946
1028
 
947
1029
  this.socket.on("reconnect_error", (error) => {
948
- this.emit("reconnectError", error);
1030
+ this.emit("error", error);
949
1031
  });
950
1032
 
951
1033
  this.socket.on("reconnect_failed", () => {
@@ -1013,10 +1095,27 @@ class Client extends EventEmitter {
1013
1095
  /**
1014
1096
  * @event Client#messageEdit
1015
1097
  */
1016
- this.socket.on('message:edited', (data) => {
1017
- const { messageId, content, editedAt } = data;
1018
- this._updateMessageContent(messageId, content, editedAt);
1019
- this.emit('messageEdit', data);
1098
+ this.socket.on('message:edited', async (data) => {
1099
+ const { messageId: id, content, editedAt } = data;
1100
+
1101
+ let msg;
1102
+ for (const [channelId, messages] of this.cache.channels) {
1103
+ const channel = messages;
1104
+ if (channel.messages.has(id)) {
1105
+ msg = channel.messages.get(id);
1106
+ msg.content = content;
1107
+ msg.editedAt = editedAt;
1108
+ msg.edited = true;
1109
+ break;
1110
+ }
1111
+ }
1112
+
1113
+ if (!msg) {
1114
+ msg = await this._processSocketMessage(data);
1115
+ this._cacheMessage(msg);
1116
+ }
1117
+
1118
+ this.emit('messageEdit', msg);
1020
1119
  });
1021
1120
 
1022
1121
  /**
@@ -1231,12 +1330,21 @@ class Client extends EventEmitter {
1231
1330
  const msg = new Message(data, this);
1232
1331
 
1233
1332
  if (!msg.author && data.user_id) {
1234
- msg.author = new User({
1235
- id: data.user_id,
1236
- username: data.username,
1237
- display_name: data.display_name,
1238
- avatar_url: data.avatar_url
1239
- }, this);
1333
+ const cachedUser = this.cache.users.get(data.user_id);
1334
+ if (cachedUser) {
1335
+ cachedUser.username = data.username || cachedUser.username;
1336
+ cachedUser.displayName = data.display_name || cachedUser.displayName;
1337
+ cachedUser.avatarUrl = formatUrl(data.avatar_url) || cachedUser.avatarUrl;
1338
+ msg.author = cachedUser;
1339
+ } else {
1340
+ msg.author = new User({
1341
+ id: data.user_id,
1342
+ username: data.username,
1343
+ display_name: data.display_name,
1344
+ avatar_url: data.avatar_url,
1345
+ }, this);
1346
+ this.cache.users.set(msg.author.id, msg.author);
1347
+ }
1240
1348
  }
1241
1349
 
1242
1350
  if (!msg.channel && data.channel_id) {
@@ -1247,6 +1355,15 @@ class Client extends EventEmitter {
1247
1355
  await msg.channel.members.fetch();
1248
1356
  }
1249
1357
 
1358
+ if (!msg.sticker && data.sticker_id) {
1359
+ let sticker = this.cache.stickers.get(data.sticker_id);
1360
+
1361
+ if (!sticker) {
1362
+ sticker = await this.fetchSticker(data.sticker_id).catch(() => null);
1363
+ }
1364
+
1365
+ msg.sticker = sticker;
1366
+ }
1250
1367
  return msg;
1251
1368
  }
1252
1369
 
@@ -1263,10 +1380,8 @@ class Client extends EventEmitter {
1263
1380
  const channel = msg.channel;
1264
1381
  this._ensureCached(this.cache.channels, channel.id, channel);
1265
1382
 
1266
- // guarda a mensagem no canal
1267
1383
  channel.messages.set(msg.id, msg);
1268
1384
 
1269
- // limita a 50 mensagens
1270
1385
  if (channel.messages.size > 50) {
1271
1386
  const firstKey = channel.messages.firstKey(); // método do Collection
1272
1387
  channel.messages.delete(firstKey);
@@ -1435,11 +1550,41 @@ class Client extends EventEmitter {
1435
1550
  throw new ClientError(`File upload error: ${error.message}`, 'UPLOAD_FAILED');
1436
1551
  }
1437
1552
  }
1553
+
1554
+ // ============================================================================
1555
+ // EVENT EMITTER OVERRIDES
1556
+ // ============================================================================
1557
+
1558
+ /**
1559
+ * Attaches an event listener.
1560
+ * @superInternal
1561
+ * @template {keyof ClientEvents} K
1562
+ * @param {K} event The event name.
1563
+ * @param {(arg: ClientEvents[K]) => void} listener
1564
+ * @returns {this}
1565
+ */
1566
+ on(event, listener) {
1567
+ return super.on(event, listener);
1568
+ }
1569
+
1570
+ /**
1571
+ * Emits an event with typed arguments.
1572
+ * @internal
1573
+ * @template {keyof ClientEvents} K
1574
+ * @param {K} event
1575
+ * @param {ClientEvents[K]} payload
1576
+ * @returns {this}
1577
+ */
1578
+ emit(event, payload) {
1579
+ return super.emit(event, payload);
1580
+ }
1438
1581
  }
1439
1582
 
1583
+ /**
1584
+ * @internal
1585
+ */
1440
1586
  class ClientError extends Error {
1441
1587
  /**
1442
- * @private
1443
1588
  * @param {string} message - Error message
1444
1589
  * @param {string} code - Error code
1445
1590
  */
package/README.md CHANGED
@@ -1,29 +1,55 @@
1
- # Beniocord.js
1
+ # Getting Started
2
2
 
3
- **Beniocord.js** is a Node.js library for creating bots easily, with basic moderation features, automatic responses, and event handling.
3
+ ## Introduction <span style="font-size:0.8em;">Intro</span>
4
4
 
5
- > ⚠️ This is an early version — meant to give you a starting point for building your bot.
5
+ ### Beniocord.js
6
+
7
+ A powerful JavaScript library for building Beniocord bots with ease.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/beniocord.js?color=crimson&logo=npm&style=flat-square)](https://www.npmjs.com/package/beniocord.js)
10
+ [![npm downloads](https://img.shields.io/npm/dt/beniocord.js?color=crimson&logo=npm&style=flat-square)](https://www.npmjs.com/package/beniocord.js)
11
+ [![GitHub stars](https://img.shields.io/github/stars/Junior37534/beniocord.js?color=yellow&logo=github&style=flat-square)](https://github.com/Junior37534/beniocord.js)
12
+ [![GitHub issues](https://img.shields.io/github/issues/Junior37534/beniocord.js?color=green&logo=github&style=flat-square)](https://github.com/Junior37534/beniocord.js/issues)
13
+ [![Join Beniocord](https://img.shields.io/badge/Join-Beniocord-5865F2?style=flat-square&logoColor=white)](https://beniocord.site/register)
14
+ [![Better Stack Badge](https://uptime.betterstack.com/status-badges/v2/monitor/284m0.svg)](https://uptime.betterstack.com/?utm_source=status_badge)
15
+
16
+ ---
17
+
18
+ ### About
19
+
20
+ Beniocord.js is a powerful Node.js module that allows you to easily interact with the Beniocord API. It provides an intuitive and modern approach to bot development.
21
+
22
+ ### Features
23
+
24
+ - 🚀 Easy to use and beginner-friendly
25
+ - ⚡ Fast and efficient
26
+ - 📦 Object-oriented design
27
+ - 🔄 Promise-based architecture
28
+ - 🎯 Full Beniocord API coverage
29
+ - 💪 TypeScript support
30
+
31
+ ### Requirements
32
+
33
+ - Node.js >= 18
34
+ - NPM >= 9
6
35
 
7
36
  ---
8
37
 
9
38
  ## Installation
10
39
 
40
+ Install via NPM:
41
+
11
42
  ```bash
12
43
  npm install beniocord.js
13
- ```
14
-
15
- > Make sure you have Node.js >= 18 installed.
44
+ ````
16
45
 
17
46
  ---
18
47
 
19
- ## Basic Example
48
+ ## Quick Example
20
49
 
21
50
  ```js
22
- const Client = require("beniocord.js");
23
- const { MessageEmbed } = Client;
24
- require('dotenv').config();
25
-
26
- const client = new Client({ token: process.env.BOT_TOKEN });
51
+ const Beniocord = require("beniocord.js");
52
+ const client = new Beniocord({ token: 'YOUR_BOT_TOKEN' });
27
53
 
28
54
  client.on("ready", () => {
29
55
  console.log("🤖 Bot connected!");
@@ -31,20 +57,21 @@ client.on("ready", () => {
31
57
 
32
58
  client.on("messageCreate", async (msg) => {
33
59
  if (msg.author?.id === client.user?.id) return;
34
- if (!msg.content) return;
60
+ if (!msg.content.startsWith('!')) return;
35
61
 
36
- if (msg.content.toLowerCase() === "!ping") {
37
- await client.sendMessage(msg.channel.id, "🏓 Pong!");
38
- }
39
-
40
- if (msg.content.toLowerCase() === "!embed") {
41
- const embed = new MessageEmbed()
42
- .setTitle("Hello from Beniocord!")
43
- .setDescription("This is an example embed")
44
- .setColor("#147bba")
45
- .setFooter(msg.author.displayName, msg.author.avatarURL());
46
-
47
- await msg.reply(embed);
62
+ const comando = msg.content.slice('!'.length).split(' ')[0];
63
+ const args = msg.content.slice(comando.length + '!'.length + 1).trim().split(' ');
64
+
65
+ if (comando === "ping") {
66
+ const msgTimestamp = Date.now() - Date.parse(msg.createdAt);
67
+ const sent = await msg.channel.send("🏓 Pinging...");
68
+ const editTimestamp = Date.now() - Date.parse(sent.createdAt);
69
+
70
+ await sent.edit(
71
+ `🏓 **Pong!**\n` +
72
+ `📨 **Message → Bot:** ${msgTimestamp}ms\n` +
73
+ `✏️ **Send → Edit:** ${editTimestamp}ms`
74
+ );
48
75
  }
49
76
  });
50
77
 
@@ -53,24 +80,8 @@ client.login();
53
80
 
54
81
  ---
55
82
 
56
- ## Features
57
-
58
- * **Basic events**: `messageCreate`, `messageEdit`, `messageDelete`, `memberJoin`, `memberLeave`, `presenceUpdate`, `channelUpdate`, and more.
59
- * **Basic moderation**: delete messages, edit messages, etc.
60
- * **Embeds support**: create rich messages with `MessageEmbed`.
61
- * **Event-driven**: easy to handle events in real-time.
62
-
63
- ---
64
-
65
- ## Events
66
-
67
- ```js
68
- client.on("messageCreate", msg => {...});
69
- client.on("memberJoin", data => {...});
70
- client.on("channelUpdate", data => {...});
71
- // and many more...
72
- ```
73
-
74
- You can add custom events and interact with your bot in real-time.
83
+ ## Useful Links
75
84
 
76
- ---
85
+ * [Official Website](https://beniocord.site)
86
+ * [Documentation](https://docs.beniocord.site)
87
+ * [Join Beniocord](https://beniocord.site/register)
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "socket.io-client": "^4.8.1"
6
6
  },
7
7
  "name": "beniocord.js",
8
- "version": "2.1.0",
8
+ "version": "2.1.2",
9
9
  "description": "Uma biblioteca leve e intuitiva para integração com APIs de bots em plataformas de mensagens, como Discord. Facilita o envio de mensagens, gerenciamento de canais e interação com usuários, proporcionando uma experiência de desenvolvimento ágil e eficiente.",
10
10
  "main": "Client.js",
11
11
  "scripts": {
@@ -3,7 +3,45 @@ const MessageCollector = require('./MessageCollector');
3
3
  const Collection = require('@discordjs/collection').Collection;
4
4
 
5
5
  let client;
6
+
7
+ /**
8
+ * @internal
9
+ */
6
10
  class Channel {
11
+ /**
12
+ * Creates a new Channel instance.
13
+ * @param {Object} data - Raw channel data.
14
+ * @param {string|number} data.id - The unique ID of the channel.
15
+ * @param {string} data.name - The name of the channel.
16
+ * @param {string} [data.description] - The channel description.
17
+ * @param {string} [data.type="text"] - The type of the channel (text, voice, etc.).
18
+ * @param {string} [data.icon_url] - The URL of the channel icon.
19
+ * @param {string|number} data.created_by - ID of the channel owner.
20
+ * @param {boolean} [data.is_private=false] - Whether the channel is private.
21
+ * @param {boolean} [data.is_locked=false] - Whether the channel is locked.
22
+ * @param {number|string} [data.member_count=0] - Number of members in the channel.
23
+ * @param {string|Date} data.created_at - Creation timestamp.
24
+ * @param {string|Date} data.updated_at - Last update timestamp.
25
+ * @param {import('./Client')} clientInstance - The client instance.
26
+ * @returns {Channel} The created Channel instance.
27
+ * @example
28
+ * // msg.channel
29
+ * Channel {
30
+ * id: 2,
31
+ * name: 'Privado',
32
+ * description: 'DM Privada para conversar secretas!\n',
33
+ * type: 'text',
34
+ * iconUrl: 'https://api.beniocord.site/uploads/1762899895145-938680330.gif',
35
+ * ownerId: 1,
36
+ * isPrivate: true,
37
+ * isLocked: false,
38
+ * memberCount: 8,
39
+ * createdAt: '2025-09-21T15:28:43.610Z',
40
+ * updatedAt: '2025-11-11T23:49:54.906Z',
41
+ * members: Collection(0) [Map] { fetch: [AsyncFunction (anonymous)] },
42
+ * messages: Collection(0) [Map] { fetch: [AsyncFunction (anonymous)] }
43
+ * }
44
+ */
7
45
  constructor(data, clientInstance) {
8
46
  client = clientInstance;
9
47
 
@@ -19,6 +57,10 @@ class Channel {
19
57
  this.createdAt = data.created_at;
20
58
  this.updatedAt = data.updated_at;
21
59
 
60
+ /**
61
+ * Cached members of the channel.
62
+ * @type {Collection<string, import('./User')>}
63
+ */
22
64
  this.members = new Collection();
23
65
  this.members.fetch = async () => {
24
66
  const members = await client.fetchChannelMembers(this.id);
@@ -29,6 +71,10 @@ class Channel {
29
71
  return this.members;
30
72
  };
31
73
 
74
+ /**
75
+ * Cached messages of the channel.
76
+ * @type {Collection<string, import('./Message')>}
77
+ */
32
78
  this.messages = new Collection();
33
79
  this.messages.fetch = async (id) => {
34
80
  if (client.fetchMessage) {
@@ -46,22 +92,40 @@ class Channel {
46
92
  });
47
93
  }
48
94
 
95
+ /**
96
+ * Sends a message to the channel.
97
+ * @param {string|Object} content - The content of the message.
98
+ * @param {Object} [opts] - Optional message options.
99
+ * @returns {Promise<import('./Message')>} The sent message.
100
+ */
49
101
  async send(content, opts = {}) {
50
102
  return client.sendMessage(this.id, content, opts);
51
103
  }
52
104
 
105
+ /**
106
+ * Starts typing indicator in the channel.
107
+ * @returns {Promise<void>}
108
+ */
53
109
  startTyping() {
54
110
  return client.startTyping(this.id);
55
111
  }
56
112
 
113
+ /**
114
+ * Stops typing indicator in the channel.
115
+ * @returns {Promise<void>}
116
+ */
57
117
  stopTyping() {
58
118
  return client.stopTyping(this.id);
59
119
  }
60
120
 
121
+ /**
122
+ * Creates a new message collector in this channel.
123
+ * @param {Object} [options={}] - Collector options.
124
+ * @returns {MessageCollector} The created message collector.
125
+ */
61
126
  createMessageCollector(options = {}) {
62
127
  return new MessageCollector(this, options, client);
63
128
  }
64
-
65
129
  }
66
130
 
67
131
  module.exports = Channel;
@@ -1,14 +1,59 @@
1
1
  const { formatUrl } = require("../helpers");
2
2
 
3
+ /**
4
+ * @internal
5
+ */
3
6
  class Emoji {
7
+ /**
8
+ * Creates a new Emoji instance.
9
+ * @param {Object} data - Raw emoji data.
10
+ * @param {string|number} data.id - The unique ID of the emoji.
11
+ * @param {string|number} data.user_id - The ID of the user who uploaded the emoji.
12
+ * @param {string} data.name - The name of the emoji.
13
+ * @param {string} data.url - The URL of the emoji image.
14
+ * @param {string|number|Date} data.created_at - Timestamp when the emoji was created.
15
+ * @returns {Emoji} The created Emoji instance.
16
+ * @example
17
+ * Emoji {
18
+ * id: 1,
19
+ * userId: 1,
20
+ * name: 'shitcord',
21
+ * url: 'https://api.beniocord.site/uploads/emojis/1758982533925-364594757.png',
22
+ * createdAt: '2025-09-27T14:15:33.932Z'
23
+ * }
24
+ *
25
+ */
4
26
  constructor(data) {
27
+ /**
28
+ * The unique ID of the emoji.
29
+ * @type {string|number}
30
+ */
5
31
  this.id = data.id;
32
+
33
+ /**
34
+ * The ID of the user who uploaded the emoji.
35
+ * @type {string|number}
36
+ */
6
37
  this.userId = data.user_id;
38
+
39
+ /**
40
+ * The name of the emoji.
41
+ * @type {string}
42
+ */
7
43
  this.name = data.name;
44
+
45
+ /**
46
+ * The URL of the emoji image.
47
+ * @type {string}
48
+ */
8
49
  this.url = formatUrl(data.url);
50
+
51
+ /**
52
+ * Timestamp when the emoji was created.
53
+ * @type {string|number|Date}
54
+ */
9
55
  this.createdAt = data.created_at;
10
- this.updatedAt = data.updated_at;
11
56
  }
12
57
  }
13
58
 
14
- module.exports = Emoji;
59
+ module.exports = Emoji;
@@ -5,7 +5,7 @@ const { formatUrl } = require('../helpers/index');
5
5
  let client;
6
6
 
7
7
  /**
8
- * Represents a message in a channel.
8
+ * @internal
9
9
  */
10
10
  class Message {
11
11
  /**
@@ -20,14 +20,58 @@ class Message {
20
20
  * @param {Object} [data.user] - Author user data.
21
21
  * @param {Object} [data.channel] - Channel data where the message was sent.
22
22
  * @param {string|number} [data.reply_to] - ID of the message this is replying to.
23
- * @param {string|number} [data.sticker_id] - ID of a sticker attached to the message.
23
+ * @param {Object} [data.sticker] - Sticker object attached to the message.
24
24
  * @param {string|number|Date} [data.edited_at] - Timestamp when the message was edited.
25
25
  * @param {string|number|Date} [data.created_at] - Timestamp when the message was created.
26
- * @param {Object} clientInstance - The client instance to send/edit/delete messages.
26
+ * @param {Object} clientInstance - The client instance.
27
+ * @returns {Message} The created Message instance.
27
28
  * @example
28
- * // Creating a message instance
29
- * const msg = new Message({ id: 1, content: "Hello!" }, client);
30
- *
29
+ * Message {
30
+ * id: 20711,
31
+ * content: 'Hello World!',
32
+ * messageType: 'text',
33
+ * fileUrl: null,
34
+ * fileName: null,
35
+ * fileSize: null,
36
+ * attachments: [],
37
+ * replyTo: 20709,
38
+ * editedAt: null,
39
+ * createdAt: '2025-11-16T14:29:40.598Z',
40
+ * sticker: {
41
+ * id: 1,
42
+ * name: 'carrin',
43
+ * url: '/uploads/stickers/1758986081574-510376341.gif',
44
+ * tags: [],
45
+ * user_id: 2,
46
+ * owner: 'kkauabr'
47
+ * },
48
+ * author: User {
49
+ * id: 1,
50
+ * username: 'junior9244',
51
+ * displayName: 'Junior',
52
+ * avatarUrl: 'https://api.beniocord.site/uploads/avatars/1760736025811-629632107.png',
53
+ * status: 'online',
54
+ * emblems: [],
55
+ * isBot: false,
56
+ * lastSeen: '2025-11-16T14:29:40.598Z',
57
+ * createdAt: '2025-11-16T14:29:40.598Z'
58
+ * },
59
+ * channel: Channel {
60
+ * id: 2,
61
+ * name: 'Privado',
62
+ * description: 'DM Privada para conversar secretas!\n',
63
+ * type: 'text',
64
+ * iconUrl: 'https://api.beniocord.site/uploads/1762899895145-938680330.gif',
65
+ * ownerId: 1,
66
+ * isPrivate: true,
67
+ * isLocked: false,
68
+ * memberCount: 8,
69
+ * createdAt: '2025-09-21T15:28:43.610Z',
70
+ * updatedAt: '2025-11-11T23:49:54.906Z',
71
+ * members: Collection(0) [Map] { fetch: [AsyncFunction (anonymous)] },
72
+ * messages: Collection(0) [Map] { fetch: [AsyncFunction (anonymous)] }
73
+ * }
74
+ * }
31
75
  */
32
76
  constructor(data, clientInstance) {
33
77
  this.id = data.id;
@@ -38,10 +82,11 @@ class Message {
38
82
  this.fileSize = data.file_size;
39
83
  this.attachments = [];
40
84
  this.replyTo = data.reply_to;
41
- this.stickerId = data.sticker_id;
42
85
  this.editedAt = data.edited_at;
43
86
  this.createdAt = data.created_at;
44
87
 
88
+ this.sticker = null;
89
+
45
90
  if (data.file_url) {
46
91
  this.attachments.push({
47
92
  url: this.fileUrl,
@@ -1,45 +1,68 @@
1
1
  const EventEmitter = require('events');
2
2
 
3
3
  class MessageCollector extends EventEmitter {
4
+ /**
5
+ * Creates a new MessageCollector.
6
+ *
7
+ * @param {Channel} channel - The channel to listen for messages.
8
+ * @param {Object} [options={}] - Options for the collector.
9
+ * @param {function(Message): boolean|Promise<boolean>} [options.filter] - Filter function to determine which messages are collected.
10
+ * @param {number} [options.time=60000] - Time in milliseconds before the collector stops automatically.
11
+ * @param {number} [options.max=Infinity] - Maximum number of messages to collect before stopping.
12
+ * @param {Client} client - The client instance to listen for events.
13
+ *
14
+ * @example
15
+ * const collector = new MessageCollector(channel, { filter: msg => msg.content.includes('hello'), time: 30000 }, client);
16
+ * collector.on('collect', msg => console.log(`Collected message: ${msg.content}`));
17
+ * collector.on('end', (collected, reason) => console.log(`Collector ended: ${reason}, collected ${collected.length} messages`));
18
+ */
4
19
  constructor(channel, options = {}, client) {
5
20
  super();
6
-
21
+
7
22
  this.channel = channel;
8
23
  this.client = client;
9
- // this.client = channel.client;
10
24
  this.filter = options.filter || (() => true);
11
25
  this.time = options.time || 60000;
12
26
  this.max = options.max || Infinity;
13
27
  this.collected = [];
14
28
  this.ended = false;
15
-
29
+
16
30
  this._timeout = null;
17
31
  this._handleMessage = this._handleMessage.bind(this);
18
-
32
+
19
33
  this._setup();
20
34
  }
21
-
35
+
36
+ /**
37
+ * Initializes event listeners and timeout for automatic stop.
38
+ * @private
39
+ */
22
40
  _setup() {
23
41
  this.client.on('messageCreate', this._handleMessage);
24
-
42
+
25
43
  if (this.time) {
26
44
  this._timeout = setTimeout(() => {
27
45
  this.stop('time');
28
46
  }, this.time);
29
47
  }
30
48
  }
31
-
49
+
50
+ /**
51
+ * Internal handler for incoming messages.
52
+ * @param {Message} message - The message received.
53
+ * @private
54
+ */
32
55
  async _handleMessage(message) {
33
56
  if (this.ended) return;
34
57
  if (message.channel.id !== this.channel.id) return;
35
-
58
+
36
59
  try {
37
60
  const filterResult = await this.filter(message);
38
61
  if (!filterResult) return;
39
-
62
+
40
63
  this.collected.push(message);
41
64
  this.emit('collect', message);
42
-
65
+
43
66
  if (this.collected.length >= this.max) {
44
67
  this.stop('limit');
45
68
  }
@@ -47,28 +70,40 @@ class MessageCollector extends EventEmitter {
47
70
  this.emit('error', error);
48
71
  }
49
72
  }
50
-
51
- stop(reason = 'user', ) {
73
+
74
+ /**
75
+ * Stops the collector manually or automatically.
76
+ *
77
+ * @param {string} [reason='user'] - Reason for stopping ('user', 'time', 'limit', etc.).
78
+ * @fires MessageCollector#end
79
+ */
80
+ stop(reason = 'user') {
52
81
  if (this.ended) return;
53
-
82
+
54
83
  this.ended = true;
55
-
84
+
56
85
  if (this._timeout) {
57
86
  clearTimeout(this._timeout);
58
87
  this._timeout = null;
59
88
  }
60
-
89
+
61
90
  this.client.removeListener('messageCreate', this._handleMessage);
62
91
  this.emit('end', this.collected, reason);
63
92
  }
64
-
93
+
94
+ /**
95
+ * Resets the timer for the collector.
96
+ *
97
+ * @param {Object} [options={}] - Options to override current timer.
98
+ * @param {number} [options.time] - New time in milliseconds to set.
99
+ */
65
100
  resetTimer(options = {}) {
66
101
  if (this._timeout) {
67
102
  clearTimeout(this._timeout);
68
103
  }
69
-
104
+
70
105
  const time = options.time || this.time;
71
-
106
+
72
107
  if (time) {
73
108
  this._timeout = setTimeout(() => {
74
109
  this.stop('time');
@@ -77,4 +112,23 @@ class MessageCollector extends EventEmitter {
77
112
  }
78
113
  }
79
114
 
80
- module.exports = MessageCollector;
115
+ /**
116
+ * Emitted when a message is successfully collected.
117
+ * @event MessageCollector#collect
118
+ * @param {Message} message - The collected message.
119
+ */
120
+
121
+ /**
122
+ * Emitted when the collector ends.
123
+ * @event MessageCollector#end
124
+ * @param {Message[]} collected - Array of collected messages.
125
+ * @param {string} reason - Reason the collector ended.
126
+ */
127
+
128
+ /**
129
+ * Emitted when an error occurs inside the collector.
130
+ * @event MessageCollector#error
131
+ * @param {Error} error - The error encountered.
132
+ */
133
+
134
+ module.exports = MessageCollector;
@@ -0,0 +1,75 @@
1
+ const { formatUrl } = require("../helpers");
2
+
3
+ /**
4
+ * @internal
5
+ */
6
+ class Sticker {
7
+ /**
8
+ * Creates a new Sticker instance.
9
+ * @param {Object} data - Raw sticker data.
10
+ * @param {string|number} data.id - The unique ID of the sticker.
11
+ * @param {string|number} data.user_id - The ID of the user who uploaded the sticker.
12
+ * @param {string} data.name - The name of the sticker.
13
+ * @param {string} data.url - The URL of the sticker image.
14
+ * @param {string[]|null} data.tags - Array of tags associated with the sticker.
15
+ * @param {string|number|Date} data.created_at - Timestamp when the sticker was created.
16
+ * @param {string|number|Date} data.updated_at - Timestamp when the sticker was last updated.
17
+ * @returns {Sticker} The created Sticker instance.
18
+ *
19
+ * @example
20
+ * Sticker {
21
+ * id: 2,
22
+ * userId: 1,
23
+ * name: 'saboroso',
24
+ * url: 'https://api.beniocord.site/uploads/stickers/1758986145335-603013635.png',
25
+ * tags: [ 'sabor', 'delicia', 'gostoso' ],
26
+ * createdAt: '2025-09-27T15:15:45.555Z',
27
+ * updatedAt: '2025-09-27T15:15:45.555Z'
28
+ * }
29
+ */
30
+ constructor(data) {
31
+ /**
32
+ * The unique ID of the sticker.
33
+ * @type {string|number}
34
+ */
35
+ this.id = data.id;
36
+
37
+ /**
38
+ * The ID of the user who uploaded the sticker.
39
+ * @type {string|number}
40
+ */
41
+ this.userId = data.user_id;
42
+
43
+ /**
44
+ * The name of the sticker.
45
+ * @type {string}
46
+ */
47
+ this.name = data.name;
48
+
49
+ /**
50
+ * Array of tags for the sticker.
51
+ * @type {string[]}
52
+ */
53
+ this.tags = Array.isArray(data.tags) ? data.tags : [];
54
+
55
+ /**
56
+ * The formatted URL of the sticker image.
57
+ * @type {string}
58
+ */
59
+ this.url = formatUrl(data.url);
60
+
61
+ /**
62
+ * Timestamp when the sticker was created.
63
+ * @type {string|number|Date}
64
+ */
65
+ this.createdAt = data.created_at;
66
+
67
+ /**
68
+ * Timestamp when the sticker was last updated.
69
+ * @type {string|number|Date}
70
+ */
71
+ this.updatedAt = data.updated_at;
72
+ }
73
+ }
74
+
75
+ module.exports = Sticker;
@@ -1,5 +1,8 @@
1
+ const { formatUrl } = require("../helpers");
2
+ let client;
3
+
1
4
  /**
2
- * Represents a user.
5
+ * @internal
3
6
  */
4
7
  class User {
5
8
  /**
@@ -10,13 +13,28 @@ class User {
10
13
  * @param {string} data.display_name - The display name of the user.
11
14
  * @param {string} data.avatar_url - The URL of the user's avatar.
12
15
  * @param {string} [data.status='offline'] - The user's status.
13
- * @param {Array<string>} [data.emblems=[]] - Array of user emblems.
16
+ * @param {Array<Object>} [data.emblems=[]] - Array of user emblems.
14
17
  * @param {boolean} data.is_bot - Whether the user is a bot.
15
18
  * @param {string|number|Date} data.last_seen - Last seen timestamp.
16
19
  * @param {string|number|Date} data.created_at - Account creation timestamp.
17
- * @param {Object} client - The client instance (optional, internal use).
20
+ * @param {import('./Client')} clientInstance - The client instance.
21
+ * @returns {User} The created User instance.
22
+ * @example
23
+ * User {
24
+ * id: 1,
25
+ * username: 'junior9244',
26
+ * displayName: 'Junior',
27
+ * avatarUrl: 'https://api.beniocord.site/uploads/avatars/1760736025811-629632107.png',
28
+ * status: 'online',
29
+ * emblems: [ [Object], [Object] ],
30
+ * isBot: false,
31
+ * lastSeen: '2025-11-16T14:44:19.394Z',
32
+ * createdAt: '2025-09-21T15:00:07.753Z'
33
+ * }
18
34
  */
19
- constructor(data, client) {
35
+ constructor(data, clientInstance) {
36
+ client = clientInstance;
37
+
20
38
  this.id = data.id;
21
39
  this.username = data.username;
22
40
  this.displayName = data.display_name;
@@ -31,10 +49,26 @@ class User {
31
49
  /**
32
50
  * Returns the avatar URL of the user.
33
51
  * @returns {string} The avatar URL.
52
+ * @example
53
+ * https://api.beniocord.site/uploads/avatars/1760736025811-629632107.png
34
54
  */
35
55
  avatarURL() {
36
56
  return this.avatarUrl;
37
57
  }
58
+
59
+ /**
60
+ * Fetches or refreshes this user from the API.
61
+ * @param {boolean} [force=false] - Whether to force fetch even if cached.
62
+ * @returns {Promise<User>} The updated User instance.
63
+ * @example
64
+ * const freshUser = await user.fetch();
65
+ */
66
+ async fetch(force = false) {
67
+ if (!client) throw new Error("Client instance not available.");
68
+ const updatedUser = await client.fetchUser(this.id, force);
69
+ Object.assign(this, updatedUser);
70
+ return this;
71
+ }
38
72
  }
39
73
 
40
- module.exports = User;
74
+ module.exports = User;
@@ -562,10 +562,21 @@ MessageEmbed.Colors = {
562
562
  };
563
563
 
564
564
  /**
565
- * MessageAttachment - Para anexos
566
565
  * @class
567
566
  */
568
567
  class MessageAttachment {
568
+ /**
569
+ * Creates a new MessageAttachment instance.
570
+ *
571
+ * @param {Buffer|Uint8Array|string} buffer - The data of the attachment. Can be a Buffer, Uint8Array, or base64 string.
572
+ * @param {string} name - The name of the attachment file (e.g., "image.png").
573
+ *
574
+ * @throws {Error} If the buffer is not provided.
575
+ * @throws {Error} If the name is not a valid string.
576
+ *
577
+ * @example
578
+ * const attachment = new MessageAttachment(fileBuffer, "photo.png");
579
+ */
569
580
  constructor(buffer, name) {
570
581
  if (!buffer) {
571
582
  throw new Error('Attachment buffer is required');