beniocord.js 2.1.1 → 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.
package/Client.js CHANGED
@@ -9,8 +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");
13
- const { formatUrl } = require("./helpers");
15
+ const { formatUrl, stripDomain } = require("./helpers");
14
16
 
15
17
  let global = {
16
18
  token: "",
@@ -57,22 +59,25 @@ class Client extends EventEmitter {
57
59
  * @fires Client#typingStop
58
60
  * @class Client
59
61
  * @description The main class of BenioCord.js, responsible for managing API communication and bot events.
60
- * @param {Object} options - Opções de configuração do cliente
61
- * @param {string} options.token - Token do bot para autenticação
62
+ * @param {Object} options - Client configuration options
63
+ * @param {string} options.token - Bot token used for authentication
64
+ * @param {string} options.api_url - Override default API URL
62
65
  * @example
63
66
  * const Beniocord = require('beniocord.js');
64
67
  * const client = new Beniocord({ token: 'YOUR_BOT_TOKEN' });
65
68
  * client.login();
66
69
  */
67
- constructor({ token }) {
70
+ constructor({ token, api_url } = {}) {
68
71
  super();
69
72
 
73
+ const API_URL = api_url ?? global.apiUrl;
74
+
70
75
  if (!token || typeof token !== 'string' || token.trim() === '') {
71
76
  throw new ClientError("Valid token is required", "INVALID_TOKEN");
72
77
  }
73
78
 
74
- // Global configuration
75
79
  global.token = token.trim();
80
+ global.apiUrl = API_URL;
76
81
 
77
82
  // Client state
78
83
  this.socket = null;
@@ -84,9 +89,9 @@ class Client extends EventEmitter {
84
89
 
85
90
  // Configuration options
86
91
  this.config = {
87
- connectionTimeout: 15000,
88
- requestTimeout: 10000,
89
- maxRetries: 3,
92
+ connectionTimeout: 999999,
93
+ requestTimeout: 999999,
94
+ maxRetries: 9999,
90
95
  reconnectionDelay: 1000,
91
96
  };
92
97
 
@@ -616,31 +621,57 @@ class Client extends EventEmitter {
616
621
  * Edits a message
617
622
  * @param {string} messageId - Message ID
618
623
  * @param {string} newContent - New message content
619
- * @returns {Promise<Object>} Response data
624
+ * @returns {Promise<Message>} Response data
620
625
  */
621
626
  async editMessage(messageId, newContent) {
622
627
  return new Promise((resolve, reject) => {
623
- try {
624
- this._ensureConnected();
625
- } catch (error) {
626
- return reject(error);
627
- }
628
-
629
628
  this.socket.emit(
630
629
  'message:edit',
631
630
  { messageId, content: newContent },
632
- (response) => {
631
+ async (response) => {
633
632
  if (response && response.error) {
634
633
  reject(new ClientError(response.error, "EDIT_ERROR"));
635
634
  } else {
636
635
  this._updateMessageContent(messageId, newContent, new Date().toISOString());
637
- resolve(response);
636
+ const msg = await this._processSocketMessage(response); // transforma response em Message
637
+ resolve(msg);
638
638
  }
639
639
  }
640
640
  );
641
641
  });
642
642
  }
643
643
 
644
+ /**
645
+ * Sends a sticker to a channel.
646
+ * Prioriza o cache. Se não tiver, faz fetch.
647
+ * @param {string|number} channelId
648
+ * @param {string|number} stickerId
649
+ * @returns {Promise<Message>}
650
+ */
651
+ async sendSticker(channelId, stickerId) {
652
+ let sticker = this.cache.stickers.get(stickerId);
653
+
654
+ if (!sticker) {
655
+ sticker = await this.fetchSticker(stickerId);
656
+ }
657
+
658
+ if (!sticker) {
659
+ throw new ClientError(`Sticker ${stickerId} not found`, "INVALID_STICKER");
660
+ }
661
+
662
+ const stickerPath = sticker.url;
663
+ if (!stickerPath) {
664
+ throw new ClientError(`Sticker ${stickerId} is missing 'url'`, "INVALID_STICKER_PATH");
665
+ }
666
+
667
+ return this.sendMessage(channelId, "", {
668
+ messageType: "sticker",
669
+ stickerId,
670
+ url: stripDomain(stickerPath),
671
+ });
672
+ }
673
+
674
+
644
675
  /**
645
676
  * Deletes a message
646
677
  * @param {string} messageId - Message ID
@@ -727,11 +758,7 @@ class Client extends EventEmitter {
727
758
  created_at: raw.created_at,
728
759
  };
729
760
  const messageData = { ...raw, user: userData };
730
-
731
- // Cria a mensagem
732
761
  const message = new Message(messageData, this);
733
-
734
- // Cache do author
735
762
  if (message.author) this.cache.users.set(message.author.id, message.author);
736
763
 
737
764
  // --- CHANNEL ---
@@ -744,6 +771,21 @@ class Client extends EventEmitter {
744
771
  message.channel = channel;
745
772
  }
746
773
 
774
+ // --- STICKER ---
775
+ if (!message.sticker && raw.sticker_id) {
776
+ let sticker = this.cache.stickers.get(raw.sticker_id);
777
+
778
+ if (!sticker) {
779
+ try {
780
+ sticker = await this.fetchSticker(raw.sticker_id);
781
+ } catch (_) {
782
+ sticker = null;
783
+ }
784
+ }
785
+
786
+ message.sticker = sticker;
787
+ }
788
+
747
789
  return message;
748
790
  } catch (error) {
749
791
  throw error instanceof ClientError
@@ -856,8 +898,9 @@ class Client extends EventEmitter {
856
898
 
857
899
  try {
858
900
  const res = await this._axios.get(`/api/stickers/${id}`);
859
- this.cache.stickers.set(res.data.id, res.data);
860
- return res.data;
901
+ const sticker = new Sticker(res.data);
902
+ this.cache.stickers.set(sticker.id, sticker);
903
+ return sticker;
861
904
  } catch (error) {
862
905
  throw error instanceof ClientError
863
906
  ? error
@@ -1085,10 +1128,27 @@ class Client extends EventEmitter {
1085
1128
  /**
1086
1129
  * @event Client#messageEdit
1087
1130
  */
1088
- this.socket.on('message:edited', (data) => {
1089
- const { messageId, content, editedAt } = data;
1090
- this._updateMessageContent(messageId, content, editedAt);
1091
- this.emit('messageEdit', data);
1131
+ this.socket.on('message:edited', async (data) => {
1132
+ const { messageId: id, content, editedAt } = data;
1133
+
1134
+ let msg;
1135
+ for (const [channelId, messages] of this.cache.channels) {
1136
+ const channel = messages;
1137
+ if (channel.messages.has(id)) {
1138
+ msg = channel.messages.get(id);
1139
+ msg.content = content;
1140
+ msg.editedAt = editedAt;
1141
+ msg.edited = true;
1142
+ break;
1143
+ }
1144
+ }
1145
+
1146
+ if (!msg) {
1147
+ msg = await this._processSocketMessage(data);
1148
+ this._cacheMessage(msg);
1149
+ }
1150
+
1151
+ this.emit('messageEdit', msg);
1092
1152
  });
1093
1153
 
1094
1154
  /**
@@ -1324,10 +1384,19 @@ class Client extends EventEmitter {
1324
1384
  msg.channel = await this.fetchChannel(data.channel_id);
1325
1385
  }
1326
1386
 
1327
- if (msg.channel.memberCount !== msg.channel.members.size) {
1387
+ if (msg.channel?.memberCount !== msg.channel?.members?.size) {
1328
1388
  await msg.channel.members.fetch();
1329
1389
  }
1330
1390
 
1391
+ if (!msg.sticker && data.sticker_id) {
1392
+ let sticker = this.cache.stickers.get(data.sticker_id);
1393
+
1394
+ if (!sticker) {
1395
+ sticker = await this.fetchSticker(data.sticker_id).catch(() => null);
1396
+ }
1397
+
1398
+ msg.sticker = sticker;
1399
+ }
1331
1400
  return msg;
1332
1401
  }
1333
1402
 
@@ -1344,10 +1413,8 @@ class Client extends EventEmitter {
1344
1413
  const channel = msg.channel;
1345
1414
  this._ensureCached(this.cache.channels, channel.id, channel);
1346
1415
 
1347
- // guarda a mensagem no canal
1348
1416
  channel.messages.set(msg.id, msg);
1349
1417
 
1350
- // limita a 50 mensagens
1351
1418
  if (channel.messages.size > 50) {
1352
1419
  const firstKey = channel.messages.firstKey(); // método do Collection
1353
1420
  channel.messages.delete(firstKey);
@@ -1546,6 +1613,8 @@ class Client extends EventEmitter {
1546
1613
  }
1547
1614
  }
1548
1615
 
1616
+ const { parseErrors } = require("./helpers");
1617
+
1549
1618
  /**
1550
1619
  * @internal
1551
1620
  */
@@ -1555,7 +1624,10 @@ class ClientError extends Error {
1555
1624
  * @param {string} code - Error code
1556
1625
  */
1557
1626
  constructor(message, code) {
1558
- super(message);
1627
+ const parsed = typeof parseErrors === 'function'
1628
+ ? (code ? parseErrors(code) : parseErrors(message))
1629
+ : null;
1630
+ super(parsed || message);
1559
1631
  this.name = 'ClientError';
1560
1632
  this.code = code;
1561
1633
  }
package/README.md CHANGED
@@ -10,7 +10,8 @@ A powerful JavaScript library for building Beniocord bots with ease.
10
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
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
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)
13
+ [![Join Beniocord](https://img.shields.io/badge/Join-Beniocord-5865F2?style=flat-square&logoColor=white)](https://beniocord.site/download)
14
+ [![Better Stack Badge](https://uptime.betterstack.com/status-badges/v2/monitor/284m0.svg)](https://uptime.betterstack.com/?utm_source=status_badge)
14
15
 
15
16
  ---
16
17
 
@@ -18,21 +19,13 @@ A powerful JavaScript library for building Beniocord bots with ease.
18
19
 
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.
20
21
 
21
- ### Features
22
-
23
- - 🚀 Easy to use and beginner-friendly
24
- - ⚡ Fast and efficient
25
- - 📦 Object-oriented design
26
- - 🔄 Promise-based architecture
27
- - 🎯 Full Beniocord API coverage
28
- - 💪 TypeScript support
29
-
22
+ <!--
30
23
  ### Requirements
31
24
 
32
25
  - Node.js >= 18
33
- - NPM >= 9
26
+ - NPM >= 9 -->
34
27
 
35
- ---
28
+ <!-- --- -->
36
29
 
37
30
  ## Installation
38
31
 
@@ -83,4 +76,5 @@ client.login();
83
76
 
84
77
  * [Official Website](https://beniocord.site)
85
78
  * [Documentation](https://docs.beniocord.site)
86
- * [Join Beniocord](https://beniocord.site/register)
79
+ * [Join Beniocord](https://beniocord.site/download)
80
+ * [Uptime monitor](https://uptime.beniocord.site)
package/helpers/index.js CHANGED
@@ -1,8 +1,78 @@
1
+ const errors = {
2
+ ALREADY_FRIENDS: "You are already friends with this user.",
3
+ ALREADY_SENT: "You have already sent a friend request to this user.",
4
+ USER_BLOCKED: "You cannot send a friend request to this user.",
5
+ USER_NOT_FOUND: "User not found.",
6
+ MEMBER_NOT_FOUND: "Member not found.",
7
+ CHANNEL_NOT_FOUND: "Could not find a channel with this ID.",
8
+ MESSAGE_NOT_FOUND: "Message not found.",
9
+ FRIENDSHIP_NOT_FOUND: "Friendship not found.",
10
+ ID_OR_USERNAME_REQUIRED: "User ID or username is required.",
11
+ BOTS_CANT_BE_FRIEND: "Cannot send friend request to bots.",
12
+ CANT_BE_FRIENDS_WITH_YOURSELF: "You cannot add yourself as a friend.",
13
+ ACCESS_DENIED_CH: "Access denied to this channel.",
14
+ NOT_CH_MEMBER: "You are not a member of this channel.",
15
+ CAN_ONLY_INVITE_FRIEND: "You can only invite users who are your friends.",
16
+ USER_ALREADY_IN_CHANNEL: "User is already a member of the channel.",
17
+ USER_ADD_SUCCESS: "User added to channel successfully.",
18
+ NO_INVITE_PERMISSION: "You do not have permission to invite users.",
19
+ NO_MANAGE_PERMISSION: "You do not have permission to manage members.",
20
+ NO_REMOVE_PERMISSION: "You do not have permission to remove members.",
21
+ NO_READ_PERMISSION: "You do not have permission to read messages in this channel.",
22
+ CH_OR_MSG_ID_INVALID: "Invalid channelId or messageId.",
23
+ CH_OR_MSG_ID_MUST_BE_INTEGER: "channelId or messageId must be integers.",
24
+ CH_OR_MSG_ID_OUT_OF_RANGE: "channelId or messageId out of valid range.",
25
+ ONLY_OWNER_CAN_WTF: "Only the owner can modify another owner.",
26
+ NO_FIELDS_TO_UPDATE: "No fields to update.",
27
+ NO_FILES_UPLOADED: "No file uploaded.",
28
+ INVALID_STATUS: "Invalid status.",
29
+ ERR_CHANNEL_NAME_EMPTY: "Channel name cannot be empty.",
30
+ ERR_CHANNEL_NAME_TOO_LONG: "Channel name is too long.",
31
+ ERR_CHANNEL_NAME_INVALID_CHARS: "Channel name contains invalid characters.",
32
+ ERR_CHANNEL_DESCRIPTION_EMPTY: "Channel description cannot be empty.",
33
+ ERR_CHANNEL_DESCRIPTION_TOO_LONG: "Channel description is too long.",
34
+ ERR_CHANNEL_DESCRIPTION_INVALID_CHARS: "Channel description contains invalid characters.",
35
+ ERR_PASSWORD_TOO_SHORT: "Password must be at least 8 characters.",
36
+ ERR_PASSWORD_TOO_LONG: "Password cannot be more than 128 characters.",
37
+ ERR_PASSWORD_MISMATCH: "Passwords do not match.",
38
+ ERR_PASSWORD_SAME_AS_CURRENT: "New password cannot be the same as the current one.",
39
+ ERR_EMAIL_INVALID: "Please enter a valid email address.",
40
+ ERR_EMAIL_SAME_AS_CURRENT: "New email cannot be the same as the current one.",
41
+ ERR_PASSWORD_EMPTY: "Password is required.",
42
+ ERR_DISPLAY_NAME_EMPTY: "Display name is required.",
43
+ ERR_USERNAME_TOO_SHORT: "Username must be at least 3 characters.",
44
+ ERR_USERNAME_INVALID_CHARS: "Username can only contain lowercase letters, numbers, and underscores.",
45
+ INTERNAL_SERVER_ERROR: "Something went wrong. Please contact support.",
46
+ ERR_USERNAME_EMPTY: "Username cannot be empty.",
47
+ ERR_USERNAME_TOO_LONG: "Username is too long.",
48
+ ERR_DISPLAY_NAME_TOO_LONG: "Display name is too long.",
49
+ ERR_DISPLAY_NAME_INVALID_CHARS: "Display name contains invalid characters.",
50
+ ERR_EMAIL_EMPTY: "Email cannot be empty.",
51
+ ERR_EMAIL_TOO_LONG: "Email is too long.",
52
+ ERR_INVALID_CREDENTIALS: "Invalid credentials.",
53
+ ERR_PASSWORD_INCORRECT: "Incorrect password.",
54
+ ERR_STATUS_INVALID: "Invalid status.",
55
+ ERR_URL_TOO_LONG: "URL is too long.",
56
+ ERR_URL_INVALID: "URL is invalid.",
57
+ FILE_TOO_LARGE: "This file is too large.",
58
+ };
59
+
1
60
  function formatUrl(url) {
2
61
  const base = 'https://api.beniocord.site';
3
62
  if (!url) return null;
4
63
  if (url.startsWith(base) || url.startsWith('http')) return url;
5
64
  return base + (url.startsWith('/') ? url : '/' + url);
6
65
  }
66
+ function stripDomain(url) {
67
+ try {
68
+ const u = new URL(url);
69
+ return u.pathname;
70
+ } catch {
71
+ return url;
72
+ }
73
+ };
74
+ function parseErrors(message) {
75
+ return errors[message] || message;
76
+ }
7
77
 
8
- module.exports = { formatUrl }
78
+ module.exports = { formatUrl, stripDomain, parseErrors }
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.1",
8
+ "version": "2.1.3",
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": {
@@ -73,7 +73,7 @@ class Channel {
73
73
 
74
74
  /**
75
75
  * Cached messages of the channel.
76
- * @type {Collection<string, import('./Message')>}
76
+ * @type {Collection<string, Message>}
77
77
  */
78
78
  this.messages = new Collection();
79
79
  this.messages.fetch = async (id) => {
@@ -96,7 +96,7 @@ class Channel {
96
96
  * Sends a message to the channel.
97
97
  * @param {string|Object} content - The content of the message.
98
98
  * @param {Object} [opts] - Optional message options.
99
- * @returns {Promise<import('./Message')>} The sent message.
99
+ * @returns {Promise<Message>} The sent message.
100
100
  */
101
101
  async send(content, opts = {}) {
102
102
  return client.sendMessage(this.id, content, opts);
@@ -5,54 +5,78 @@ const { formatUrl } = require("../helpers");
5
5
  */
6
6
  class Emoji {
7
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
8
+ * Cria uma nova instância de Emoji.
9
+ * @param {Object} data - Dados crus do emoji vindos da API.
10
+ * @param {number} data.id - ID único do emoji.
11
+ * @param {number} data.owner_id - ID do dono do emoji.
12
+ * @param {string} data.name - Nome do emoji.
13
+ * @param {string} data.url - URL da imagem do emoji.
14
+ * @param {string} data.created_at - Data de criação do emoji.
15
+ * @param {boolean} data.can_use - Se o emoji pode ser usado.
16
+ * @param {string} data.username - Username do dono.
17
+ * @param {string} data.display_name - Nome de exibição do dono.
18
+ * @returns {Emoji} Instância criada de Emoji.
19
+ * @example
17
20
  * Emoji {
18
21
  * id: 1,
19
- * userId: 1,
22
+ * ownerId: 1,
20
23
  * name: 'shitcord',
21
24
  * url: 'https://api.beniocord.site/uploads/emojis/1758982533925-364594757.png',
22
- * createdAt: '2025-09-27T14:15:33.932Z'
25
+ * createdAt: '2025-09-27T14:15:33.932Z',
26
+ * canUse: true,
27
+ * username: 'benio',
28
+ * displayName: 'Benio'
23
29
  * }
24
- *
25
30
  */
26
31
  constructor(data) {
27
32
  /**
28
- * The unique ID of the emoji.
29
- * @type {string|number}
33
+ * ID único do emoji.
34
+ * @type {number}
30
35
  */
31
36
  this.id = data.id;
32
37
 
33
38
  /**
34
- * The ID of the user who uploaded the emoji.
35
- * @type {string|number}
39
+ * ID do dono do emoji.
40
+ * @type {number}
36
41
  */
37
- this.userId = data.user_id;
42
+ this.ownerId = data.owner_id;
38
43
 
39
44
  /**
40
- * The name of the emoji.
45
+ * Nome do emoji.
41
46
  * @type {string}
42
47
  */
43
48
  this.name = data.name;
44
49
 
45
50
  /**
46
- * The URL of the emoji image.
51
+ * URL formatada da imagem do emoji.
47
52
  * @type {string}
48
53
  */
49
54
  this.url = formatUrl(data.url);
50
55
 
51
56
  /**
52
- * Timestamp when the emoji was created.
53
- * @type {string|number|Date}
57
+ * Data de criação do emoji.
58
+ * @type {string}
54
59
  */
55
60
  this.createdAt = data.created_at;
61
+
62
+
63
+ /**
64
+ * Se o emoji pode ser usado.
65
+ * @type {boolean}
66
+ */
67
+ this.canUse = data.can_use;
68
+
69
+ /**
70
+ * Username do dono do emoji.
71
+ * @type {string}
72
+ */
73
+ this.username = data.username;
74
+
75
+ /**
76
+ * Nome de exibição do dono do emoji.
77
+ * @type {string}
78
+ */
79
+ this.displayName = data.display_name;
56
80
  }
57
81
  }
58
82
 
@@ -11,80 +11,82 @@ class Message {
11
11
  /**
12
12
  * Creates a new Message instance.
13
13
  * @param {Object} data - Raw message data.
14
- * @param {string|number} data.id - The unique ID of the message.
14
+ * @param {number} data.id - The unique ID of the message.
15
+ * @param {number} data.channel_id - The channel ID where the message was sent.
16
+ * @param {number} data.user_id - The user ID of the author.
15
17
  * @param {string} data.content - The content of the message.
16
- * @param {string} [data.message_type="text"] - The type of the message (text, file, etc.).
17
- * @param {string} [data.file_url] - URL of the attached file.
18
- * @param {string} [data.file_name] - Name of the attached file.
19
- * @param {number} [data.file_size] - Size of the attached file in bytes.
20
- * @param {Object} [data.user] - Author user data.
21
- * @param {Object} [data.channel] - Channel data where the message was sent.
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.
24
- * @param {string|number|Date} [data.edited_at] - Timestamp when the message was edited.
25
- * @param {string|number|Date} [data.created_at] - Timestamp when the message was created.
18
+ * @param {"text"|"image"|"video"|"audio"|"file"|"sticker"|"embed"} data.message_type - The type of the message.
19
+ * @param {string|null} data.file_url - URL of the attached file.
20
+ * @param {string|null} data.file_name - Name of the attached file.
21
+ * @param {number|null} data.file_size - Size of the attached file in bytes.
22
+ * @param {number|null} data.reply_to - ID of the message this is replying to.
23
+ * @param {string} [data.reply_content] - Content of the replied message.
24
+ * @param {string|null} [data.reply_message_type] - Type of the replied message.
25
+ * @param {string} [data.reply_username] - Username of the replied user.
26
+ * @param {string|null} [data.reply_display_name] - Display name of the replied user.
27
+ * @param {string|null} [data.reply_avatar_url] - Avatar URL of the replied user.
28
+ * @param {string|null} [data.reply_user_id] - User ID of the replied user.
29
+ * @param {string|null} data.edited_at - Timestamp when the message was edited.
30
+ * @param {string} data.created_at - Timestamp when the message was created.
31
+ * @param {number|null} [data.sticker_id] - Sticker ID attached to the message.
32
+ * @param {string|null} [data.embed_data] - Embed data if present.
26
33
  * @param {Object} clientInstance - The client instance.
27
34
  * @returns {Message} The created Message instance.
28
35
  * @example
29
36
  * Message {
30
- * id: 20711,
31
- * content: 'Hello World!',
32
- * messageType: 'text',
33
- * fileUrl: null,
34
- * fileName: null,
37
+ * id: 1875,
38
+ * channelId: 4,
39
+ * userId: 1,
40
+ * content: 'Sticker: crazy',
41
+ * messageType: 'sticker',
42
+ * fileUrl: 'https://api.beniocord.site/uploads/stickers/1765027757156-305382752.png',
43
+ * fileName: 'crazy.png',
35
44
  * fileSize: null,
36
- * attachments: [],
37
- * replyTo: 20709,
38
- * stickerId: null,
39
45
  * editedAt: null,
40
- * createdAt: '2025-11-16T14:29:40.598Z',
41
- * author: User {
42
- * id: 1,
43
- * username: 'junior9244',
44
- * displayName: 'Junior',
45
- * avatarUrl: 'https://api.beniocord.site/uploads/avatars/1760736025811-629632107.png',
46
- * status: 'online',
47
- * emblems: [],
48
- * isBot: false,
49
- * lastSeen: '2025-11-16T14:29:40.598Z',
50
- * createdAt: '2025-11-16T14:29:40.598Z'
46
+ * createdAt: '2025-12-20T20:54:46.247Z',
47
+ * stickerId: 3,
48
+ * embedData: null,
49
+ * replyToId: 1874,
50
+ * replyMessage: {
51
+ * content: 'Hello world',
52
+ * username: 'juniorcanary',
53
+ * displayName: 'Junior canary',
54
+ * avatarUrl: 'https://api.beniocord.site/uploads/avatars/1764896784903-442484585.png',
55
+ * messageType: 'text',
56
+ * userId: 1
51
57
  * },
52
- * channel: Channel {
53
- * id: 2,
54
- * name: 'Privado',
55
- * description: 'DM Privada para conversar secretas!\n',
56
- * type: 'text',
57
- * iconUrl: 'https://api.beniocord.site/uploads/1762899895145-938680330.gif',
58
- * ownerId: 1,
59
- * isPrivate: true,
60
- * isLocked: false,
61
- * memberCount: 8,
62
- * createdAt: '2025-09-21T15:28:43.610Z',
63
- * updatedAt: '2025-11-11T23:49:54.906Z',
64
- * members: Collection(0) [Map] { fetch: [AsyncFunction (anonymous)] },
65
- * messages: Collection(0) [Map] { fetch: [AsyncFunction (anonymous)] }
66
- * }
58
+ * author: User {...},
59
+ * channel: Channel {...},
60
+ * sticker: Sticker {...}
67
61
  * }
68
62
  */
69
63
  constructor(data, clientInstance) {
70
64
  this.id = data.id;
65
+ this.channelId = data.channel_id;
66
+ this.userId = data.user_id;
71
67
  this.content = data.content;
72
- this.messageType = data.message_type || "text";
73
- this.fileUrl = formatUrl(data.file_url);
74
- this.fileName = data.file_name;
75
- this.fileSize = data.file_size;
76
- this.attachments = [];
77
- this.replyTo = data.reply_to;
78
- this.stickerId = data.sticker_id;
79
- this.editedAt = data.edited_at;
68
+ this.messageType = data.message_type;
69
+ this.fileUrl = data.file_url ? formatUrl(data.file_url) : null;
70
+ this.fileName = data.file_name ?? null;
71
+ this.fileSize = data.file_size ?? null;
72
+ this.editedAt = data.edited_at ?? null;
80
73
  this.createdAt = data.created_at;
81
-
82
- if (data.file_url) {
83
- this.attachments.push({
84
- url: this.fileUrl,
85
- name: this.fileName,
86
- size: this.fileSize,
87
- });
74
+ this.stickerId = data.sticker_id ?? null;
75
+ this.embedData = data.embed_data ?? null;
76
+ // Reply fields
77
+ if (data.reply_to != null) {
78
+ this.replyToId = data.reply_to;
79
+ this.replyMessage = {
80
+ content: data.reply_content ?? '',
81
+ username: data.reply_username ?? '',
82
+ displayName: data.reply_display_name ?? null,
83
+ avatarUrl: data.reply_avatar_url ? formatUrl(data.reply_avatar_url) : null,
84
+ messageType: data.reply_message_type ?? '',
85
+ userId: data.reply_user_id ?? ''
86
+ };
87
+ } else {
88
+ this.replyToId = null;
89
+ this.replyMessage = null;
88
90
  }
89
91
 
90
92
  this.author = data.user ? new User(data.user, clientInstance) : null;
@@ -0,0 +1,98 @@
1
+ const { formatUrl } = require("../helpers");
2
+
3
+ /**
4
+ * @internal
5
+ */
6
+ class Sticker {
7
+ /**
8
+ * Cria uma nova instância de Sticker.
9
+ * @param {Object} data - Dados crus do sticker vindos da API.
10
+ * @param {number} data.id - ID único do sticker.
11
+ * @param {number} data.owner_id - ID do dono do sticker.
12
+ * @param {string} data.name - Nome do sticker.
13
+ * @param {string} data.url - URL da imagem do sticker.
14
+ * @param {string|string[]} data.tags - Tags associadas ao sticker.
15
+ * @param {string} data.created_at - Data de criação do sticker.
16
+ * @param {boolean} data.can_use - Se o sticker pode ser usado.
17
+ * @param {string} data.username - Username do dono.
18
+ * @param {string} data.display_name - Nome de exibição do dono.
19
+ * @returns {Sticker} Instância criada de Sticker.
20
+ *
21
+ * @example
22
+ * Sticker {
23
+ * id: 4,
24
+ * ownerId: 7,
25
+ * name: 'osuhow',
26
+ * tags: [],
27
+ * url: 'https://api.beniocord.site/uploads/stickers/1766100944970-73288347.png',
28
+ * createdAt: '2025-12-18T23:35:44.985Z',
29
+ * canUse: false,
30
+ * username: 'joneor',
31
+ * displayName: 'Juner'
32
+ * }
33
+ */
34
+ constructor(data) {
35
+ /**
36
+ * ID único do sticker.
37
+ * @type {number}
38
+ */
39
+ this.id = data.id;
40
+
41
+ /**
42
+ * ID do dono do sticker.
43
+ * @type {number}
44
+ */
45
+ this.ownerId = data.owner_id;
46
+
47
+ /**
48
+ * Nome do sticker.
49
+ * @type {string}
50
+ */
51
+ this.name = data.name;
52
+
53
+ /**
54
+ * Tags associadas ao sticker.
55
+ * @type {string[]}
56
+ */
57
+ if (Array.isArray(data.tags)) {
58
+ this.tags = data.tags;
59
+ } else if (typeof data.tags === 'string' && data.tags.length > 0) {
60
+ this.tags = data.tags.split(',').map(t => t.trim()).filter(Boolean);
61
+ } else {
62
+ this.tags = [];
63
+ }
64
+
65
+ /**
66
+ * URL formatada da imagem do sticker.
67
+ * @type {string}
68
+ */
69
+ this.url = formatUrl(data.url);
70
+
71
+ /**
72
+ * Data de criação do sticker.
73
+ * @type {string}
74
+ */
75
+ this.createdAt = data.created_at;
76
+
77
+
78
+ /**
79
+ * Se o sticker pode ser usado.
80
+ * @type {boolean}
81
+ */
82
+ this.canUse = data.can_use;
83
+
84
+ /**
85
+ * Username do dono do sticker.
86
+ * @type {string}
87
+ */
88
+ this.username = data.username;
89
+
90
+ /**
91
+ * Nome de exibição do dono do sticker.
92
+ * @type {string}
93
+ */
94
+ this.displayName = data.display_name;
95
+ }
96
+ }
97
+
98
+ module.exports = Sticker;
@@ -12,6 +12,7 @@ class User {
12
12
  * @param {string} data.username - The username of the user.
13
13
  * @param {string} data.display_name - The display name of the user.
14
14
  * @param {string} data.avatar_url - The URL of the user's avatar.
15
+ * @param {string|null} [data.banner_url] - The URL of the user's banner (optional).
15
16
  * @param {string} [data.status='offline'] - The user's status.
16
17
  * @param {Array<Object>} [data.emblems=[]] - Array of user emblems.
17
18
  * @param {boolean} data.is_bot - Whether the user is a bot.
@@ -25,6 +26,7 @@ class User {
25
26
  * username: 'junior9244',
26
27
  * displayName: 'Junior',
27
28
  * avatarUrl: 'https://api.beniocord.site/uploads/avatars/1760736025811-629632107.png',
29
+ * bannerUrl: 'https://api.beniocord.site/uploads/banners/1760736025811-629632107.png',
28
30
  * status: 'online',
29
31
  * emblems: [ [Object], [Object] ],
30
32
  * isBot: false,
@@ -39,11 +41,16 @@ class User {
39
41
  this.username = data.username;
40
42
  this.displayName = data.display_name;
41
43
  this.avatarUrl = formatUrl(data.avatar_url);
44
+ /**
45
+ * The URL of the user's banner (or null if not set).
46
+ * @type {string|null}
47
+ */
48
+ this.bannerUrl = data.banner_url ? formatUrl(data.banner_url) : null;
42
49
  this.status = data.status || "offline";
43
50
  this.emblems = data.emblems || [];
44
- this.isBot = data.is_bot;
45
- this.lastSeen = data.last_seen;
46
- this.createdAt = data.created_at;
51
+ this.isBot = typeof data.is_bot !== 'undefined' ? data.is_bot : null;
52
+ this.lastSeen = typeof data.last_seen !== 'undefined' ? data.last_seen : null;
53
+ this.createdAt = typeof data.created_at !== 'undefined' ? data.created_at : null;
47
54
  }
48
55
 
49
56
  /**