beniocord.js 2.1.2 → 2.1.4
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 +263 -48
- package/README.md +6 -13
- package/helpers/index.js +71 -1
- package/package.json +1 -1
- package/structures/Channel.js +2 -2
- package/structures/Emoji.js +45 -21
- package/structures/Message.js +62 -68
- package/structures/Sticker.js +55 -32
- package/structures/User.js +10 -3
- package/structures/Util.js +83 -1
package/Client.js
CHANGED
|
@@ -11,8 +11,8 @@ const Channel = require("./structures/Channel");
|
|
|
11
11
|
const Emoji = require("./structures/Emoji");
|
|
12
12
|
const Sticker = require("./structures/Sticker");
|
|
13
13
|
|
|
14
|
-
const { MessageEmbed, MessageAttachment } = require("./structures/Util");
|
|
15
|
-
const { formatUrl } = require("./helpers");
|
|
14
|
+
const { MessageEmbed, MessageAttachment, MessageImageAttachment, MessageAudioAttachment, MessageVideoAttachment } = require("./structures/Util");
|
|
15
|
+
const { formatUrl, stripDomain } = require("./helpers");
|
|
16
16
|
|
|
17
17
|
let global = {
|
|
18
18
|
token: "",
|
|
@@ -61,20 +61,23 @@ class Client extends EventEmitter {
|
|
|
61
61
|
* @description The main class of BenioCord.js, responsible for managing API communication and bot events.
|
|
62
62
|
* @param {Object} options - Client configuration options
|
|
63
63
|
* @param {string} options.token - Bot token used for authentication
|
|
64
|
+
* @param {string} options.api_url - Override default API URL
|
|
64
65
|
* @example
|
|
65
66
|
* const Beniocord = require('beniocord.js');
|
|
66
67
|
* const client = new Beniocord({ token: 'YOUR_BOT_TOKEN' });
|
|
67
68
|
* client.login();
|
|
68
69
|
*/
|
|
69
|
-
constructor({ token }) {
|
|
70
|
+
constructor({ token, api_url } = {}) {
|
|
70
71
|
super();
|
|
71
72
|
|
|
73
|
+
const API_URL = api_url ?? global.apiUrl;
|
|
74
|
+
|
|
72
75
|
if (!token || typeof token !== 'string' || token.trim() === '') {
|
|
73
76
|
throw new ClientError("Valid token is required", "INVALID_TOKEN");
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
// Global configuration
|
|
77
79
|
global.token = token.trim();
|
|
80
|
+
global.apiUrl = API_URL;
|
|
78
81
|
|
|
79
82
|
// Client state
|
|
80
83
|
this.socket = null;
|
|
@@ -86,9 +89,9 @@ class Client extends EventEmitter {
|
|
|
86
89
|
|
|
87
90
|
// Configuration options
|
|
88
91
|
this.config = {
|
|
89
|
-
connectionTimeout:
|
|
90
|
-
requestTimeout:
|
|
91
|
-
maxRetries:
|
|
92
|
+
connectionTimeout: 999999,
|
|
93
|
+
requestTimeout: 999999,
|
|
94
|
+
maxRetries: 9999,
|
|
92
95
|
reconnectionDelay: 1000,
|
|
93
96
|
};
|
|
94
97
|
|
|
@@ -538,20 +541,16 @@ class Client extends EventEmitter {
|
|
|
538
541
|
|
|
539
542
|
// Handle MessageAttachment as opts (backward compatibility)
|
|
540
543
|
if (opts instanceof MessageAttachment) {
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
messageType: detectedType
|
|
552
|
-
};
|
|
553
|
-
messageType = detectedType;
|
|
554
|
-
}
|
|
544
|
+
const fileData = await this._handleFileUpload(opts.buffer, opts.name);
|
|
545
|
+
const detectedType = opts.type || fileData.detectedType;
|
|
546
|
+
|
|
547
|
+
opts = {
|
|
548
|
+
fileUrl: fileData.url,
|
|
549
|
+
fileName: fileData.originalName,
|
|
550
|
+
fileSize: fileData.size,
|
|
551
|
+
messageType: detectedType
|
|
552
|
+
};
|
|
553
|
+
messageType = detectedType;
|
|
555
554
|
}
|
|
556
555
|
|
|
557
556
|
// Handle file upload
|
|
@@ -638,6 +637,185 @@ class Client extends EventEmitter {
|
|
|
638
637
|
});
|
|
639
638
|
}
|
|
640
639
|
|
|
640
|
+
/**
|
|
641
|
+
* Sends a sticker to a channel.
|
|
642
|
+
* Prioriza o cache. Se não tiver, faz fetch.
|
|
643
|
+
* @param {string|number} channelId
|
|
644
|
+
* @param {string|number} stickerId
|
|
645
|
+
* @returns {Promise<Message>}
|
|
646
|
+
*/
|
|
647
|
+
async sendSticker(channelId, stickerId) {
|
|
648
|
+
let sticker = this.cache.stickers.get(stickerId);
|
|
649
|
+
|
|
650
|
+
if (!sticker) {
|
|
651
|
+
sticker = await this.fetchSticker(stickerId);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (!sticker) {
|
|
655
|
+
throw new ClientError(`Sticker ${stickerId} not found`, "INVALID_STICKER");
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const stickerPath = sticker.url;
|
|
659
|
+
if (!stickerPath) {
|
|
660
|
+
throw new ClientError(`Sticker ${stickerId} is missing 'url'`, "INVALID_STICKER_PATH");
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return this.sendMessage(channelId, "", {
|
|
664
|
+
messageType: "sticker",
|
|
665
|
+
stickerId,
|
|
666
|
+
url: stripDomain(stickerPath),
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// ============================================================================
|
|
671
|
+
// PUBLIC API METHODS - File/Media Sending
|
|
672
|
+
// ============================================================================
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Sends a file to a channel
|
|
676
|
+
* @param {string} channelId - Channel ID
|
|
677
|
+
* @param {Buffer|string} file - Buffer, base64 string, or file path
|
|
678
|
+
* @param {Object} options - Send options
|
|
679
|
+
* @param {string} options.fileName - File name (required for Buffer/base64)
|
|
680
|
+
* @param {string} options.content - Optional text content to send with the file
|
|
681
|
+
* @param {string} options.replyTo - Optional message ID to reply to
|
|
682
|
+
* @returns {Promise<Message>} Sent message object
|
|
683
|
+
* @example
|
|
684
|
+
* // Send from file path
|
|
685
|
+
* client.sendFile(channelId, './document.pdf');
|
|
686
|
+
*
|
|
687
|
+
* // Send from buffer
|
|
688
|
+
* client.sendFile(channelId, buffer, { fileName: 'document.pdf' });
|
|
689
|
+
*
|
|
690
|
+
* // Send with message
|
|
691
|
+
* client.sendFile(channelId, './photo.png', { content: 'Check this out!' });
|
|
692
|
+
*/
|
|
693
|
+
async sendFile(channelId, file, options = {}) {
|
|
694
|
+
const { fileName, content = '', replyTo } = options;
|
|
695
|
+
|
|
696
|
+
try {
|
|
697
|
+
const fileData = await this._handleFileUpload(file, fileName);
|
|
698
|
+
|
|
699
|
+
return this.sendMessage(channelId, content, {
|
|
700
|
+
file: null, // Already uploaded
|
|
701
|
+
fileUrl: fileData.url,
|
|
702
|
+
fileName: fileData.originalName,
|
|
703
|
+
fileSize: fileData.size,
|
|
704
|
+
messageType: fileData.detectedType,
|
|
705
|
+
replyTo,
|
|
706
|
+
});
|
|
707
|
+
} catch (error) {
|
|
708
|
+
throw error instanceof ClientError ? error : new ClientError(error.message, "SEND_FILE_ERROR");
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Sends an image to a channel
|
|
714
|
+
* @param {string} channelId - Channel ID
|
|
715
|
+
* @param {Buffer|string} image - Buffer, base64 string, or file path
|
|
716
|
+
* @param {Object} options - Send options
|
|
717
|
+
* @param {string} options.fileName - File name (required for Buffer/base64)
|
|
718
|
+
* @param {string} options.content - Optional text content to send with the image
|
|
719
|
+
* @param {string} options.replyTo - Optional message ID to reply to
|
|
720
|
+
* @returns {Promise<Message>} Sent message object
|
|
721
|
+
* @example
|
|
722
|
+
* // Send from file path
|
|
723
|
+
* client.sendImage(channelId, './photo.png');
|
|
724
|
+
*
|
|
725
|
+
* // Send from buffer
|
|
726
|
+
* client.sendImage(channelId, imageBuffer, { fileName: 'screenshot.png' });
|
|
727
|
+
*
|
|
728
|
+
* // Send from base64
|
|
729
|
+
* client.sendImage(channelId, 'data:image/png;base64,...');
|
|
730
|
+
*/
|
|
731
|
+
async sendImage(channelId, image, options = {}) {
|
|
732
|
+
const { fileName, content = '', replyTo } = options;
|
|
733
|
+
|
|
734
|
+
try {
|
|
735
|
+
const fileData = await this._handleFileUpload(image, fileName);
|
|
736
|
+
|
|
737
|
+
return this.sendMessage(channelId, content, {
|
|
738
|
+
fileUrl: fileData.url,
|
|
739
|
+
fileName: fileData.originalName,
|
|
740
|
+
fileSize: fileData.size,
|
|
741
|
+
messageType: 'image',
|
|
742
|
+
replyTo,
|
|
743
|
+
});
|
|
744
|
+
} catch (error) {
|
|
745
|
+
throw error instanceof ClientError ? error : new ClientError(error.message, "SEND_IMAGE_ERROR");
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Sends an audio file to a channel
|
|
751
|
+
* @param {string} channelId - Channel ID
|
|
752
|
+
* @param {Buffer|string} audio - Buffer, base64 string, or file path
|
|
753
|
+
* @param {Object} options - Send options
|
|
754
|
+
* @param {string} options.fileName - File name (required for Buffer/base64)
|
|
755
|
+
* @param {string} options.content - Optional text content to send with the audio
|
|
756
|
+
* @param {string} options.replyTo - Optional message ID to reply to
|
|
757
|
+
* @returns {Promise<Message>} Sent message object
|
|
758
|
+
* @example
|
|
759
|
+
* // Send from file path
|
|
760
|
+
* client.sendAudio(channelId, './song.mp3');
|
|
761
|
+
*
|
|
762
|
+
* // Send from buffer (voice recording for example)
|
|
763
|
+
* client.sendAudio(channelId, audioBuffer, { fileName: 'voice_message.ogg' });
|
|
764
|
+
*
|
|
765
|
+
* // Send with content
|
|
766
|
+
* client.sendAudio(channelId, './podcast.mp3', { content: 'New episode!' });
|
|
767
|
+
*/
|
|
768
|
+
async sendAudio(channelId, audio, options = {}) {
|
|
769
|
+
const { fileName, content = '', replyTo } = options;
|
|
770
|
+
|
|
771
|
+
try {
|
|
772
|
+
const fileData = await this._handleFileUpload(audio, fileName);
|
|
773
|
+
|
|
774
|
+
return this.sendMessage(channelId, content, {
|
|
775
|
+
fileUrl: fileData.url,
|
|
776
|
+
fileName: fileData.originalName,
|
|
777
|
+
fileSize: fileData.size,
|
|
778
|
+
messageType: 'audio',
|
|
779
|
+
replyTo,
|
|
780
|
+
});
|
|
781
|
+
} catch (error) {
|
|
782
|
+
throw error instanceof ClientError ? error : new ClientError(error.message, "SEND_AUDIO_ERROR");
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/**
|
|
787
|
+
* Sends a video to a channel
|
|
788
|
+
* @param {string} channelId - Channel ID
|
|
789
|
+
* @param {Buffer|string} video - Buffer, base64 string, or file path
|
|
790
|
+
* @param {Object} options - Send options
|
|
791
|
+
* @param {string} options.fileName - File name (required for Buffer/base64)
|
|
792
|
+
* @param {string} options.content - Optional text content to send with the video
|
|
793
|
+
* @param {string} options.replyTo - Optional message ID to reply to
|
|
794
|
+
* @returns {Promise<Message>} Sent message object
|
|
795
|
+
* @example
|
|
796
|
+
* // Send from file path
|
|
797
|
+
* client.sendVideo(channelId, './video.mp4');
|
|
798
|
+
*
|
|
799
|
+
* // Send from buffer
|
|
800
|
+
* client.sendVideo(channelId, videoBuffer, { fileName: 'clip.mp4' });
|
|
801
|
+
*/
|
|
802
|
+
async sendVideo(channelId, video, options = {}) {
|
|
803
|
+
const { fileName, content = '', replyTo } = options;
|
|
804
|
+
|
|
805
|
+
try {
|
|
806
|
+
const fileData = await this._handleFileUpload(video, fileName);
|
|
807
|
+
|
|
808
|
+
return this.sendMessage(channelId, content, {
|
|
809
|
+
fileUrl: fileData.url,
|
|
810
|
+
fileName: fileData.originalName,
|
|
811
|
+
fileSize: fileData.size,
|
|
812
|
+
messageType: 'video',
|
|
813
|
+
replyTo,
|
|
814
|
+
});
|
|
815
|
+
} catch (error) {
|
|
816
|
+
throw error instanceof ClientError ? error : new ClientError(error.message, "SEND_VIDEO_ERROR");
|
|
817
|
+
}
|
|
818
|
+
}
|
|
641
819
|
|
|
642
820
|
/**
|
|
643
821
|
* Deletes a message
|
|
@@ -682,7 +860,28 @@ class Client extends EventEmitter {
|
|
|
682
860
|
}
|
|
683
861
|
|
|
684
862
|
const res = await this._axios.get(`/api/channels/${channelId}/messages`, { params });
|
|
685
|
-
|
|
863
|
+
|
|
864
|
+
const messages = res.data.map(raw => {
|
|
865
|
+
let userData = raw.user;
|
|
866
|
+
if (!userData && raw.user_id) {
|
|
867
|
+
userData = {
|
|
868
|
+
id: raw.user_id,
|
|
869
|
+
username: raw.username,
|
|
870
|
+
display_name: raw.display_name,
|
|
871
|
+
avatar_url: raw.avatar_url,
|
|
872
|
+
status: raw.status || 'online',
|
|
873
|
+
emblems: raw.emblems || [],
|
|
874
|
+
is_bot: raw.is_bot ?? false,
|
|
875
|
+
last_seen: raw.last_seen ?? raw.created_at,
|
|
876
|
+
created_at: raw.created_at,
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
const messageData = { ...raw, user: userData };
|
|
881
|
+
const msg = new Message(messageData, this);
|
|
882
|
+
if (msg.author) this.cache.users.set(msg.author.id, msg.author);
|
|
883
|
+
return msg;
|
|
884
|
+
});
|
|
686
885
|
|
|
687
886
|
if (!this.cache.messages.has(channelId)) {
|
|
688
887
|
this.cache.messages.set(channelId, []);
|
|
@@ -695,6 +894,24 @@ class Client extends EventEmitter {
|
|
|
695
894
|
}
|
|
696
895
|
});
|
|
697
896
|
|
|
897
|
+
let channel = this.cache.channels.get(channelId);
|
|
898
|
+
if (!channel) {
|
|
899
|
+
const id = String(channelId);
|
|
900
|
+
for (const [key, val] of this.cache.channels) {
|
|
901
|
+
if (String(key) === id) {
|
|
902
|
+
channel = val;
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if (channel) {
|
|
909
|
+
messages.forEach(msg => {
|
|
910
|
+
if (!msg.channel) msg.channel = channel;
|
|
911
|
+
channel.messages.set(msg.id, msg);
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
|
|
698
915
|
return messages;
|
|
699
916
|
} catch (error) {
|
|
700
917
|
throw error instanceof ClientError ? error : new ClientError(error.message, "FETCH_MESSAGES_ERROR");
|
|
@@ -900,30 +1117,6 @@ class Client extends EventEmitter {
|
|
|
900
1117
|
}
|
|
901
1118
|
}
|
|
902
1119
|
|
|
903
|
-
// ============================================================================
|
|
904
|
-
// PUBLIC API METHODS - File Upload
|
|
905
|
-
// ============================================================================
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
* Uploads a file to the server
|
|
909
|
-
* @param {MessageAttachment} file - File attachment to upload
|
|
910
|
-
* @returns {Promise<Object>} Upload response with file URL
|
|
911
|
-
*/
|
|
912
|
-
async uploadFile(file) {
|
|
913
|
-
try {
|
|
914
|
-
const formData = new FormData();
|
|
915
|
-
formData.append('file', file.buffer, { filename: file.name });
|
|
916
|
-
const res = await this._axios.post('/api/upload', formData, {
|
|
917
|
-
headers: formData.getHeaders(),
|
|
918
|
-
timeout: 30000
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
return res.data;
|
|
922
|
-
} catch (error) {
|
|
923
|
-
throw error instanceof ClientError ? error : new ClientError(error.message, "UPLOAD_ERROR");
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
|
|
927
1120
|
// ============================================================================
|
|
928
1121
|
// PUBLIC API METHODS - Cache Management
|
|
929
1122
|
// ============================================================================
|
|
@@ -1351,7 +1544,7 @@ class Client extends EventEmitter {
|
|
|
1351
1544
|
msg.channel = await this.fetchChannel(data.channel_id);
|
|
1352
1545
|
}
|
|
1353
1546
|
|
|
1354
|
-
if (msg.channel
|
|
1547
|
+
if (msg.channel?.memberCount !== msg.channel?.members?.size) {
|
|
1355
1548
|
await msg.channel.members.fetch();
|
|
1356
1549
|
}
|
|
1357
1550
|
|
|
@@ -1498,6 +1691,16 @@ class Client extends EventEmitter {
|
|
|
1498
1691
|
'image/webp': '.webp',
|
|
1499
1692
|
'video/mp4': '.mp4',
|
|
1500
1693
|
'video/webm': '.webm',
|
|
1694
|
+
'audio/mpeg': '.mp3',
|
|
1695
|
+
'audio/mp3': '.mp3',
|
|
1696
|
+
'audio/wav': '.wav',
|
|
1697
|
+
'audio/wave': '.wav',
|
|
1698
|
+
'audio/ogg': '.ogg',
|
|
1699
|
+
'audio/webm': '.weba',
|
|
1700
|
+
'audio/aac': '.aac',
|
|
1701
|
+
'audio/flac': '.flac',
|
|
1702
|
+
'audio/m4a': '.m4a',
|
|
1703
|
+
'audio/x-m4a': '.m4a',
|
|
1501
1704
|
};
|
|
1502
1705
|
|
|
1503
1706
|
const ext = mimeToExt[mimeType] || '.bin';
|
|
@@ -1524,11 +1727,14 @@ class Client extends EventEmitter {
|
|
|
1524
1727
|
const ext = path.extname(finalFileName).toLowerCase();
|
|
1525
1728
|
const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg'];
|
|
1526
1729
|
const videoExts = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm'];
|
|
1730
|
+
const audioExts = ['.mp3', '.wav', '.ogg', '.flac', '.aac', '.m4a', '.weba', '.opus', '.wma'];
|
|
1527
1731
|
|
|
1528
1732
|
if (imageExts.includes(ext)) {
|
|
1529
1733
|
detectedType = 'image';
|
|
1530
1734
|
} else if (videoExts.includes(ext)) {
|
|
1531
1735
|
detectedType = 'video';
|
|
1736
|
+
} else if (audioExts.includes(ext)) {
|
|
1737
|
+
detectedType = 'audio';
|
|
1532
1738
|
} else {
|
|
1533
1739
|
detectedType = 'file';
|
|
1534
1740
|
}
|
|
@@ -1580,6 +1786,8 @@ class Client extends EventEmitter {
|
|
|
1580
1786
|
}
|
|
1581
1787
|
}
|
|
1582
1788
|
|
|
1789
|
+
const { parseErrors } = require("./helpers");
|
|
1790
|
+
|
|
1583
1791
|
/**
|
|
1584
1792
|
* @internal
|
|
1585
1793
|
*/
|
|
@@ -1589,12 +1797,19 @@ class ClientError extends Error {
|
|
|
1589
1797
|
* @param {string} code - Error code
|
|
1590
1798
|
*/
|
|
1591
1799
|
constructor(message, code) {
|
|
1592
|
-
|
|
1800
|
+
const parsed = typeof parseErrors === 'function'
|
|
1801
|
+
? (code ? parseErrors(code) : parseErrors(message))
|
|
1802
|
+
: null;
|
|
1803
|
+
super(parsed || message);
|
|
1593
1804
|
this.name = 'ClientError';
|
|
1594
1805
|
this.code = code;
|
|
1595
1806
|
}
|
|
1596
1807
|
}
|
|
1597
1808
|
|
|
1598
1809
|
Client.MessageEmbed = MessageEmbed;
|
|
1810
|
+
Client.MessageAttachment = MessageAttachment;
|
|
1811
|
+
Client.MessageImageAttachment = MessageImageAttachment;
|
|
1812
|
+
Client.MessageAudioAttachment = MessageAudioAttachment;
|
|
1813
|
+
Client.MessageVideoAttachment = MessageVideoAttachment;
|
|
1599
1814
|
// Client.ClientError = ClientError;
|
|
1600
1815
|
module.exports = Client;
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A powerful JavaScript library for building Beniocord bots with ease.
|
|
|
10
10
|
[](https://www.npmjs.com/package/beniocord.js)
|
|
11
11
|
[](https://github.com/Junior37534/beniocord.js)
|
|
12
12
|
[](https://github.com/Junior37534/beniocord.js/issues)
|
|
13
|
-
[](https://beniocord.site/
|
|
13
|
+
[](https://beniocord.site/download)
|
|
14
14
|
[](https://uptime.betterstack.com/?utm_source=status_badge)
|
|
15
15
|
|
|
16
16
|
---
|
|
@@ -19,21 +19,13 @@ A powerful JavaScript library for building Beniocord bots with ease.
|
|
|
19
19
|
|
|
20
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
21
|
|
|
22
|
-
|
|
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
|
-
|
|
22
|
+
<!--
|
|
31
23
|
### Requirements
|
|
32
24
|
|
|
33
25
|
- Node.js >= 18
|
|
34
|
-
- NPM >= 9
|
|
26
|
+
- NPM >= 9 -->
|
|
35
27
|
|
|
36
|
-
---
|
|
28
|
+
<!-- --- -->
|
|
37
29
|
|
|
38
30
|
## Installation
|
|
39
31
|
|
|
@@ -84,4 +76,5 @@ client.login();
|
|
|
84
76
|
|
|
85
77
|
* [Official Website](https://beniocord.site)
|
|
86
78
|
* [Documentation](https://docs.beniocord.site)
|
|
87
|
-
* [Join Beniocord](https://beniocord.site/
|
|
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.
|
|
8
|
+
"version": "2.1.4",
|
|
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": {
|
package/structures/Channel.js
CHANGED
|
@@ -73,7 +73,7 @@ class Channel {
|
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* Cached messages of the channel.
|
|
76
|
-
* @type {Collection<string,
|
|
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<
|
|
99
|
+
* @returns {Promise<Message>} The sent message.
|
|
100
100
|
*/
|
|
101
101
|
async send(content, opts = {}) {
|
|
102
102
|
return client.sendMessage(this.id, content, opts);
|
package/structures/Emoji.js
CHANGED
|
@@ -5,54 +5,78 @@ const { formatUrl } = require("../helpers");
|
|
|
5
5
|
*/
|
|
6
6
|
class Emoji {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @param {Object} data -
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {
|
|
12
|
-
* @param {string} data.name -
|
|
13
|
-
* @param {string} data.url -
|
|
14
|
-
* @param {string
|
|
15
|
-
* @
|
|
16
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
*
|
|
29
|
-
* @type {
|
|
33
|
+
* ID único do emoji.
|
|
34
|
+
* @type {number}
|
|
30
35
|
*/
|
|
31
36
|
this.id = data.id;
|
|
32
37
|
|
|
33
38
|
/**
|
|
34
|
-
*
|
|
35
|
-
* @type {
|
|
39
|
+
* ID do dono do emoji.
|
|
40
|
+
* @type {number}
|
|
36
41
|
*/
|
|
37
|
-
this.
|
|
42
|
+
this.ownerId = data.owner_id;
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
|
-
*
|
|
45
|
+
* Nome do emoji.
|
|
41
46
|
* @type {string}
|
|
42
47
|
*/
|
|
43
48
|
this.name = data.name;
|
|
44
49
|
|
|
45
50
|
/**
|
|
46
|
-
*
|
|
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
|
-
*
|
|
53
|
-
* @type {string
|
|
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
|
|
package/structures/Message.js
CHANGED
|
@@ -11,88 +11,82 @@ class Message {
|
|
|
11
11
|
/**
|
|
12
12
|
* Creates a new Message instance.
|
|
13
13
|
* @param {Object} data - Raw message data.
|
|
14
|
-
* @param {
|
|
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 {
|
|
17
|
-
* @param {string}
|
|
18
|
-
* @param {string}
|
|
19
|
-
* @param {number}
|
|
20
|
-
* @param {
|
|
21
|
-
* @param {
|
|
22
|
-
* @param {string|
|
|
23
|
-
* @param {
|
|
24
|
-
* @param {string|
|
|
25
|
-
* @param {string|
|
|
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:
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
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
45
|
* editedAt: null,
|
|
39
|
-
* createdAt: '2025-
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
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
|
|
47
57
|
* },
|
|
48
|
-
* author: User {
|
|
49
|
-
*
|
|
50
|
-
*
|
|
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
|
-
* }
|
|
58
|
+
* author: User {...},
|
|
59
|
+
* channel: Channel {...},
|
|
60
|
+
* sticker: Sticker {...}
|
|
74
61
|
* }
|
|
75
62
|
*/
|
|
76
63
|
constructor(data, clientInstance) {
|
|
77
64
|
this.id = data.id;
|
|
65
|
+
this.channelId = data.channel_id;
|
|
66
|
+
this.userId = data.user_id;
|
|
78
67
|
this.content = data.content;
|
|
79
|
-
this.messageType = data.message_type
|
|
80
|
-
this.fileUrl = formatUrl(data.file_url);
|
|
81
|
-
this.fileName = data.file_name;
|
|
82
|
-
this.fileSize = data.file_size;
|
|
83
|
-
this.
|
|
84
|
-
this.replyTo = data.reply_to;
|
|
85
|
-
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;
|
|
86
73
|
this.createdAt = data.created_at;
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
if (data.
|
|
91
|
-
this.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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;
|
|
96
90
|
}
|
|
97
91
|
|
|
98
92
|
this.author = data.user ? new User(data.user, clientInstance) : null;
|
package/structures/Sticker.js
CHANGED
|
@@ -5,70 +5,93 @@ const { formatUrl } = require("../helpers");
|
|
|
5
5
|
*/
|
|
6
6
|
class Sticker {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @param {Object} data -
|
|
10
|
-
* @param {
|
|
11
|
-
* @param {
|
|
12
|
-
* @param {string} data.name -
|
|
13
|
-
* @param {string} data.url -
|
|
14
|
-
* @param {string[]
|
|
15
|
-
* @param {string
|
|
16
|
-
* @param {
|
|
17
|
-
* @
|
|
18
|
-
*
|
|
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
|
+
*
|
|
19
21
|
* @example
|
|
20
22
|
* Sticker {
|
|
21
|
-
* id:
|
|
22
|
-
*
|
|
23
|
-
* name: '
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* createdAt: '2025-
|
|
27
|
-
*
|
|
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'
|
|
28
32
|
* }
|
|
29
33
|
*/
|
|
30
34
|
constructor(data) {
|
|
31
35
|
/**
|
|
32
|
-
*
|
|
33
|
-
* @type {
|
|
36
|
+
* ID único do sticker.
|
|
37
|
+
* @type {number}
|
|
34
38
|
*/
|
|
35
39
|
this.id = data.id;
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @type {
|
|
42
|
+
* ID do dono do sticker.
|
|
43
|
+
* @type {number}
|
|
40
44
|
*/
|
|
41
|
-
this.
|
|
45
|
+
this.ownerId = data.owner_id;
|
|
42
46
|
|
|
43
47
|
/**
|
|
44
|
-
*
|
|
48
|
+
* Nome do sticker.
|
|
45
49
|
* @type {string}
|
|
46
50
|
*/
|
|
47
51
|
this.name = data.name;
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
|
-
*
|
|
54
|
+
* Tags associadas ao sticker.
|
|
51
55
|
* @type {string[]}
|
|
52
56
|
*/
|
|
53
|
-
|
|
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
|
+
}
|
|
54
64
|
|
|
55
65
|
/**
|
|
56
|
-
*
|
|
66
|
+
* URL formatada da imagem do sticker.
|
|
57
67
|
* @type {string}
|
|
58
68
|
*/
|
|
59
69
|
this.url = formatUrl(data.url);
|
|
60
70
|
|
|
61
71
|
/**
|
|
62
|
-
*
|
|
63
|
-
* @type {string
|
|
72
|
+
* Data de criação do sticker.
|
|
73
|
+
* @type {string}
|
|
64
74
|
*/
|
|
65
75
|
this.createdAt = data.created_at;
|
|
66
76
|
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Se o sticker pode ser usado.
|
|
80
|
+
* @type {boolean}
|
|
81
|
+
*/
|
|
82
|
+
this.canUse = data.can_use;
|
|
83
|
+
|
|
67
84
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @type {string
|
|
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}
|
|
70
93
|
*/
|
|
71
|
-
this.
|
|
94
|
+
this.displayName = data.display_name;
|
|
72
95
|
}
|
|
73
96
|
}
|
|
74
97
|
|
package/structures/User.js
CHANGED
|
@@ -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
|
/**
|
package/structures/Util.js
CHANGED
|
@@ -586,7 +586,89 @@ class MessageAttachment {
|
|
|
586
586
|
}
|
|
587
587
|
this.buffer = buffer;
|
|
588
588
|
this.name = name;
|
|
589
|
+
this.type = this._detectType();
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Detects the file type based on extension
|
|
594
|
+
* @private
|
|
595
|
+
* @returns {string} The detected type
|
|
596
|
+
*/
|
|
597
|
+
_detectType() {
|
|
598
|
+
const ext = this.name.split('.').pop().toLowerCase();
|
|
599
|
+
|
|
600
|
+
const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg'];
|
|
601
|
+
const videoExts = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm'];
|
|
602
|
+
const audioExts = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a', 'weba', 'opus', 'wma'];
|
|
603
|
+
|
|
604
|
+
if (imageExts.includes(ext)) return 'image';
|
|
605
|
+
if (videoExts.includes(ext)) return 'video';
|
|
606
|
+
if (audioExts.includes(ext)) return 'audio';
|
|
607
|
+
return 'file';
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* @class
|
|
613
|
+
*/
|
|
614
|
+
class MessageImageAttachment extends MessageAttachment {
|
|
615
|
+
/**
|
|
616
|
+
* Creates a new MessageImageAttachment instance.
|
|
617
|
+
*
|
|
618
|
+
* @param {Buffer|Uint8Array|string} buffer - The image data.
|
|
619
|
+
* @param {string} name - The name of the image file (e.g., "screenshot.png").
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* const image = new MessageImageAttachment(imageBuffer, "screenshot.png");
|
|
623
|
+
*/
|
|
624
|
+
constructor(buffer, name) {
|
|
625
|
+
super(buffer, name);
|
|
626
|
+
this.type = 'image';
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* @class
|
|
632
|
+
*/
|
|
633
|
+
class MessageAudioAttachment extends MessageAttachment {
|
|
634
|
+
/**
|
|
635
|
+
* Creates a new MessageAudioAttachment instance.
|
|
636
|
+
*
|
|
637
|
+
* @param {Buffer|Uint8Array|string} buffer - The audio data.
|
|
638
|
+
* @param {string} name - The name of the audio file (e.g., "voice_message.mp3").
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* const audio = new MessageAudioAttachment(audioBuffer, "song.mp3");
|
|
642
|
+
*/
|
|
643
|
+
constructor(buffer, name) {
|
|
644
|
+
super(buffer, name);
|
|
645
|
+
this.type = 'audio';
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* @class
|
|
651
|
+
*/
|
|
652
|
+
class MessageVideoAttachment extends MessageAttachment {
|
|
653
|
+
/**
|
|
654
|
+
* Creates a new MessageVideoAttachment instance.
|
|
655
|
+
*
|
|
656
|
+
* @param {Buffer|Uint8Array|string} buffer - The video data.
|
|
657
|
+
* @param {string} name - The name of the video file (e.g., "video.mp4").
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* const video = new MessageVideoAttachment(videoBuffer, "clip.mp4");
|
|
661
|
+
*/
|
|
662
|
+
constructor(buffer, name) {
|
|
663
|
+
super(buffer, name);
|
|
664
|
+
this.type = 'video';
|
|
589
665
|
}
|
|
590
666
|
}
|
|
591
667
|
|
|
592
|
-
module.exports = {
|
|
668
|
+
module.exports = {
|
|
669
|
+
MessageEmbed,
|
|
670
|
+
MessageAttachment,
|
|
671
|
+
MessageImageAttachment,
|
|
672
|
+
MessageAudioAttachment,
|
|
673
|
+
MessageVideoAttachment
|
|
674
|
+
};
|