discord-self-lite 0.1.4 → 0.1.6
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/package.json +1 -1
- package/src/classes/BitField.js +116 -0
- package/src/classes/Channel.js +112 -0
- package/src/classes/Guild.js +3 -0
- package/src/classes/GuildMember.js +47 -4
- package/src/classes/Permissions.js +212 -0
- package/src/connection/rest/RestManager.js +5 -4
- package/src/connection/webhook/WebhookClient.js +26 -4
- package/src/index.js +16 -0
package/package.json
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A BitField is a data structure that makes it easy to interact with a bitfield.
|
|
3
|
+
*/
|
|
4
|
+
class BitField {
|
|
5
|
+
/**
|
|
6
|
+
* @param {BitFieldResolvable} [bits=BitField.defaultBit] Bit(s) to read from
|
|
7
|
+
*/
|
|
8
|
+
constructor(bits = BitField.defaultBit) {
|
|
9
|
+
/**
|
|
10
|
+
* Bitfield of the packed bits
|
|
11
|
+
* @type {bigint}
|
|
12
|
+
*/
|
|
13
|
+
this.bitfield = BitField.resolve(bits);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Checks whether the bitfield has a bit, or any of multiple bits.
|
|
18
|
+
* @param {BitFieldResolvable} bit Bit(s) to check for
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
any(bit) {
|
|
22
|
+
return (this.bitfield & BitField.resolve(bit)) !== BitField.defaultBit;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether the bitfield has a bit, or multiple bits.
|
|
27
|
+
* @param {BitFieldResolvable} bit Bit(s) to check for
|
|
28
|
+
* @returns {boolean}
|
|
29
|
+
*/
|
|
30
|
+
has(bit) {
|
|
31
|
+
bit = BitField.resolve(bit);
|
|
32
|
+
return (this.bitfield & bit) === bit;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Gets all given bits that are missing from the bitfield.
|
|
37
|
+
* @param {BitFieldResolvable} bits Bit(s) to check for
|
|
38
|
+
* @returns {string[]}
|
|
39
|
+
*/
|
|
40
|
+
missing(bits) {
|
|
41
|
+
const res = [];
|
|
42
|
+
const bit = BitField.resolve(bits);
|
|
43
|
+
|
|
44
|
+
for (const [flag, value] of Object.entries(this.constructor.FLAGS)) {
|
|
45
|
+
if ((bit & value) !== value) continue;
|
|
46
|
+
if ((this.bitfield & value) === value) continue;
|
|
47
|
+
res.push(flag);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return res;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Gets an {@link Array} of bitfield names based on the bits available.
|
|
55
|
+
* @param {boolean} [has=true] Whether to show bits that are set
|
|
56
|
+
* @returns {string[]}
|
|
57
|
+
*/
|
|
58
|
+
toArray(has = true) {
|
|
59
|
+
const arr = [];
|
|
60
|
+
|
|
61
|
+
for (const [flag, value] of Object.entries(this.constructor.FLAGS)) {
|
|
62
|
+
if (has) {
|
|
63
|
+
if ((this.bitfield & value) === value) arr.push(flag);
|
|
64
|
+
} else {
|
|
65
|
+
if ((this.bitfield & value) !== value) arr.push(flag);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return arr;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Data that can be resolved to give a bitfield. This can be:
|
|
74
|
+
* * A string (see {@link BitField.FLAGS})
|
|
75
|
+
* * A bit number
|
|
76
|
+
* * An instance of BitField
|
|
77
|
+
* * An Array of BitFieldResolvable
|
|
78
|
+
* @typedef {string|bigint|BitField|BitFieldResolvable[]} BitFieldResolvable
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolves bitfields to their numeric form.
|
|
83
|
+
* @param {BitFieldResolvable} [bit=BitField.defaultBit] bit(s) to resolve
|
|
84
|
+
* @returns {bigint}
|
|
85
|
+
*/
|
|
86
|
+
static resolve(bit = BitField.defaultBit) {
|
|
87
|
+
if (typeof bit === "bigint" && bit >= BitField.defaultBit) return bit;
|
|
88
|
+
if (bit instanceof BitField) return bit.bitfield;
|
|
89
|
+
if (Array.isArray(bit))
|
|
90
|
+
return bit
|
|
91
|
+
.map((p) => this.resolve(p))
|
|
92
|
+
.reduce((prev, p) => prev | p, BitField.defaultBit);
|
|
93
|
+
if (typeof bit === "string") {
|
|
94
|
+
// Check if it's a numeric string (permission bitfield from API)
|
|
95
|
+
if (/^\d+$/.test(bit)) return BigInt(bit);
|
|
96
|
+
// Otherwise treat as flag name
|
|
97
|
+
return this.FLAGS[bit];
|
|
98
|
+
}
|
|
99
|
+
if (typeof bit === "number") return BigInt(bit);
|
|
100
|
+
throw new TypeError("BitField.resolve: Invalid bitfield");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Numeric bitfield flags.
|
|
106
|
+
* @type {Object<string, bigint>}
|
|
107
|
+
*/
|
|
108
|
+
BitField.FLAGS = {};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The default bit to use if none are provided.
|
|
112
|
+
* @type {bigint}
|
|
113
|
+
*/
|
|
114
|
+
BitField.defaultBit = 0n;
|
|
115
|
+
|
|
116
|
+
module.exports = BitField;
|
package/src/classes/Channel.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Represents a Discord channel
|
|
3
3
|
*/
|
|
4
|
+
const Permissions = require("./Permissions");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Safe BigInt conversion
|
|
8
|
+
* @param {*} value - Value to convert to BigInt
|
|
9
|
+
* @returns {bigint} BigInt representation
|
|
10
|
+
*/
|
|
11
|
+
function toBigInt(value) {
|
|
12
|
+
if (typeof value === "bigint") return value;
|
|
13
|
+
if (typeof value === "string") return BigInt(value);
|
|
14
|
+
if (typeof value === "number") return BigInt(value);
|
|
15
|
+
return 0n;
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
class Channel {
|
|
5
19
|
/**
|
|
6
20
|
* Create a new Channel instance
|
|
@@ -161,6 +175,104 @@ class Channel {
|
|
|
161
175
|
const guildId = this.data.guild_id;
|
|
162
176
|
return `https://discord.com/channels/${guildId}/${this.id}`;
|
|
163
177
|
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Check permissions for a member in this channel
|
|
181
|
+
* @param {GuildMember} member - The guild member to check permissions for
|
|
182
|
+
* @returns {Permissions} Permissions bitfield for this member in this channel
|
|
183
|
+
*/
|
|
184
|
+
permissionsFor(member) {
|
|
185
|
+
if (!member?.permissions) return new Permissions(toBigInt(0));
|
|
186
|
+
|
|
187
|
+
// Start with the member's base guild permissions
|
|
188
|
+
let permissions = member.permissions.bitfield;
|
|
189
|
+
|
|
190
|
+
// If member has administrator, they have all permissions
|
|
191
|
+
if (member.permissions.has(Permissions.FLAGS.ADMINISTRATOR)) {
|
|
192
|
+
return new Permissions(Permissions.ALL);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Apply channel permission overwrites
|
|
196
|
+
if (this.data.permission_overwrites) {
|
|
197
|
+
const overwrites = this.data.permission_overwrites;
|
|
198
|
+
|
|
199
|
+
// Role overwrites (deny takes precedence over allow)
|
|
200
|
+
const memberRoles = member.roles || [];
|
|
201
|
+
for (const overwrite of overwrites) {
|
|
202
|
+
if (overwrite.type === 0) {
|
|
203
|
+
// Role overwrite
|
|
204
|
+
if (
|
|
205
|
+
memberRoles.includes(overwrite.id) ||
|
|
206
|
+
overwrite.id === this.data.guild_id
|
|
207
|
+
) {
|
|
208
|
+
permissions &= ~toBigInt(overwrite.deny || 0);
|
|
209
|
+
permissions |= toBigInt(overwrite.allow || 0);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Member-specific overwrites (takes precedence over role overwrites)
|
|
215
|
+
const memberOverwrite = overwrites.find(
|
|
216
|
+
(ow) => ow.type === 1 && ow.id === member.id,
|
|
217
|
+
);
|
|
218
|
+
if (memberOverwrite) {
|
|
219
|
+
permissions &= ~toBigInt(memberOverwrite.deny || 0);
|
|
220
|
+
permissions |= toBigInt(memberOverwrite.allow || 0);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return new Permissions(permissions);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Wait for a message in this channel
|
|
229
|
+
* @param {object} [options={}] - Options for awaiting messages
|
|
230
|
+
* @param {Function} [options.filter] - Filter function for messages (must return true/false)
|
|
231
|
+
* @param {number} [options.time=30000] - Timeout in milliseconds
|
|
232
|
+
* @param {boolean} [options.errors=true] - Whether to reject on timeout
|
|
233
|
+
* @returns {Promise<Message>} The matching message
|
|
234
|
+
* @throws {Error} If timeout is reached and errors is true
|
|
235
|
+
* @example
|
|
236
|
+
* // Wait for any message
|
|
237
|
+
* const msg = await channel.awaitMessage();
|
|
238
|
+
*
|
|
239
|
+
* // Wait for a message from specific user
|
|
240
|
+
* const msg = await channel.awaitMessage({
|
|
241
|
+
* filter: (m) => m.author.id === '123456789',
|
|
242
|
+
* time: 60000
|
|
243
|
+
* });
|
|
244
|
+
*
|
|
245
|
+
* // Wait for message with specific content patterns
|
|
246
|
+
* const msg = await channel.awaitMessage({
|
|
247
|
+
* filter: (m) => m.author.id === userId &&
|
|
248
|
+
* (m.content.includes('yes') || m.content.includes('confirm')),
|
|
249
|
+
* time: 30000
|
|
250
|
+
* });
|
|
251
|
+
*/
|
|
252
|
+
async awaitMessage(options = {}) {
|
|
253
|
+
const { filter = () => true, time = 30000, errors = true } = options;
|
|
254
|
+
|
|
255
|
+
return new Promise((resolve, reject) => {
|
|
256
|
+
const listener = (message) => {
|
|
257
|
+
if (message.channelId === this.id && filter(message)) {
|
|
258
|
+
this.client.removeListener("messageCreate", listener);
|
|
259
|
+
clearTimeout(timeout);
|
|
260
|
+
resolve(message);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const timeout = setTimeout(() => {
|
|
265
|
+
this.client.removeListener("messageCreate", listener);
|
|
266
|
+
if (errors) {
|
|
267
|
+
reject(new Error("Message await timed out"));
|
|
268
|
+
} else {
|
|
269
|
+
resolve(null);
|
|
270
|
+
}
|
|
271
|
+
}, time);
|
|
272
|
+
|
|
273
|
+
this.client.on("messageCreate", listener);
|
|
274
|
+
});
|
|
275
|
+
}
|
|
164
276
|
}
|
|
165
277
|
|
|
166
278
|
module.exports = Channel;
|
package/src/classes/Guild.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Represents a Discord guild member
|
|
3
3
|
*/
|
|
4
|
+
const Permissions = require("./Permissions");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Safe BigInt conversion
|
|
8
|
+
* @param {*} value - Value to convert to BigInt
|
|
9
|
+
* @returns {bigint} BigInt representation
|
|
10
|
+
*/
|
|
11
|
+
function toBigInt(value) {
|
|
12
|
+
if (typeof value === "bigint") return value;
|
|
13
|
+
if (typeof value === "string") return BigInt(value);
|
|
14
|
+
if (typeof value === "number") return BigInt(value);
|
|
15
|
+
return 0n;
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
class GuildMember {
|
|
5
19
|
/**
|
|
6
20
|
* Create a new GuildMember instance
|
|
@@ -50,16 +64,45 @@ class GuildMember {
|
|
|
50
64
|
|
|
51
65
|
/**
|
|
52
66
|
* Get the member's permissions in this guild
|
|
53
|
-
* @returns {
|
|
67
|
+
* @returns {Permissions} Permissions bitfield
|
|
54
68
|
*/
|
|
55
69
|
get permissions() {
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
if (this._permissions) return this._permissions;
|
|
71
|
+
|
|
72
|
+
// Calculate permissions based on roles
|
|
73
|
+
let permissions = 0n;
|
|
74
|
+
|
|
75
|
+
// If member is the guild owner, they have all permissions
|
|
76
|
+
if (this.id === this.guild.ownerId) {
|
|
77
|
+
permissions = Permissions.ALL;
|
|
78
|
+
} else {
|
|
79
|
+
// Start with @everyone role permissions
|
|
80
|
+
const everyoneRole = this.guild.roles?.find(
|
|
81
|
+
(role) => role.id === this.guild.id,
|
|
82
|
+
);
|
|
83
|
+
if (everyoneRole && everyoneRole.permissions != null) {
|
|
84
|
+
permissions |= toBigInt(everyoneRole.permissions);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Add permissions from member's roles
|
|
88
|
+
for (const roleId of this.roles || []) {
|
|
89
|
+
const role = this.guild.roles?.find((r) => r.id === roleId);
|
|
90
|
+
if (role && role.permissions != null) {
|
|
91
|
+
permissions |= toBigInt(role.permissions);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this._permissions = new Permissions(permissions);
|
|
58
97
|
return this._permissions;
|
|
59
98
|
}
|
|
60
99
|
|
|
61
100
|
set permissions(value) {
|
|
62
|
-
|
|
101
|
+
if (value instanceof Permissions) {
|
|
102
|
+
this._permissions = value;
|
|
103
|
+
} else {
|
|
104
|
+
this._permissions = new Permissions(value);
|
|
105
|
+
}
|
|
63
106
|
}
|
|
64
107
|
|
|
65
108
|
/**
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const BitField = require("./BitField");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of
|
|
7
|
+
* permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member
|
|
8
|
+
* that override their default permissions.
|
|
9
|
+
* @extends {BitField}
|
|
10
|
+
*/
|
|
11
|
+
class Permissions extends BitField {
|
|
12
|
+
/**
|
|
13
|
+
* Bitfield of the packed bits
|
|
14
|
+
* @type {bigint}
|
|
15
|
+
* @name Permissions#bitfield
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Data that can be resolved to give a permission number. This can be:
|
|
20
|
+
* * A string (see {@link Permissions.FLAGS})
|
|
21
|
+
* * A permission number
|
|
22
|
+
* * An instance of Permissions
|
|
23
|
+
* * An Array of PermissionResolvable
|
|
24
|
+
* @typedef {string|bigint|Permissions|PermissionResolvable[]} PermissionResolvable
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets all given bits that are missing from the bitfield.
|
|
29
|
+
* @param {BitFieldResolvable} bits Bit(s) to check for
|
|
30
|
+
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
|
31
|
+
* @returns {string[]}
|
|
32
|
+
*/
|
|
33
|
+
missing(bits, checkAdmin = true) {
|
|
34
|
+
return checkAdmin && this.has(this.constructor.FLAGS.ADMINISTRATOR)
|
|
35
|
+
? []
|
|
36
|
+
: super.missing(bits);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Checks whether the bitfield has a permission, or any of multiple permissions.
|
|
41
|
+
* @param {PermissionResolvable} permission Permission(s) to check for
|
|
42
|
+
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
any(permission, checkAdmin = true) {
|
|
46
|
+
return (
|
|
47
|
+
(checkAdmin && super.has(this.constructor.FLAGS.ADMINISTRATOR)) ||
|
|
48
|
+
super.any(permission)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Checks whether the bitfield has a permission, or multiple permissions.
|
|
54
|
+
* @param {PermissionResolvable} permission Permission(s) to check for
|
|
55
|
+
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
|
56
|
+
* @returns {boolean}
|
|
57
|
+
*/
|
|
58
|
+
has(permission, checkAdmin = true) {
|
|
59
|
+
return (
|
|
60
|
+
(checkAdmin && super.has(this.constructor.FLAGS.ADMINISTRATOR)) ||
|
|
61
|
+
super.has(permission)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Gets an {@link Array} of bitfield names based on the permissions available.
|
|
67
|
+
* @returns {string[]}
|
|
68
|
+
*/
|
|
69
|
+
toArray() {
|
|
70
|
+
return super.toArray(false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Numeric permission flags. All available properties:
|
|
76
|
+
* * `CREATE_INSTANT_INVITE` (create invitations to the guild)
|
|
77
|
+
* * `KICK_MEMBERS`
|
|
78
|
+
* * `BAN_MEMBERS`
|
|
79
|
+
* * `ADMINISTRATOR` (implicitly has *all* permissions, and bypasses all channel overwrites)
|
|
80
|
+
* * `MANAGE_CHANNELS` (edit and reorder channels)
|
|
81
|
+
* * `MANAGE_GUILD` (edit the guild information, region, etc.)
|
|
82
|
+
* * `ADD_REACTIONS` (add new reactions to messages)
|
|
83
|
+
* * `VIEW_AUDIT_LOG`
|
|
84
|
+
* * `PRIORITY_SPEAKER`
|
|
85
|
+
* * `STREAM`
|
|
86
|
+
* * `VIEW_CHANNEL`
|
|
87
|
+
* * `SEND_MESSAGES`
|
|
88
|
+
* * `SEND_TTS_MESSAGES`
|
|
89
|
+
* * `MANAGE_MESSAGES` (delete messages and reactions)
|
|
90
|
+
* * `EMBED_LINKS` (links posted will have a preview embedded)
|
|
91
|
+
* * `ATTACH_FILES`
|
|
92
|
+
* * `READ_MESSAGE_HISTORY` (view messages that were posted prior to opening Discord)
|
|
93
|
+
* * `MENTION_EVERYONE`
|
|
94
|
+
* * `USE_EXTERNAL_EMOJIS` (use emojis from different guilds)
|
|
95
|
+
* * `VIEW_GUILD_INSIGHTS`
|
|
96
|
+
* * `CONNECT` (connect to a voice channel)
|
|
97
|
+
* * `SPEAK` (speak in a voice channel)
|
|
98
|
+
* * `MUTE_MEMBERS` (mute members across all voice channels)
|
|
99
|
+
* * `DEAFEN_MEMBERS` (deafen members across all voice channels)
|
|
100
|
+
* * `MOVE_MEMBERS` (move members between voice channels)
|
|
101
|
+
* * `USE_VAD` (use voice activity detection)
|
|
102
|
+
* * `CHANGE_NICKNAME`
|
|
103
|
+
* * `MANAGE_NICKNAMES` (change other members' nicknames)
|
|
104
|
+
* * `MANAGE_ROLES`
|
|
105
|
+
* * `MANAGE_WEBHOOKS`
|
|
106
|
+
* * `MANAGE_EMOJIS_AND_STICKERS`
|
|
107
|
+
* * `USE_APPLICATION_COMMANDS`
|
|
108
|
+
* * `REQUEST_TO_SPEAK`
|
|
109
|
+
* * `MANAGE_EVENTS`
|
|
110
|
+
* * `MANAGE_THREADS`
|
|
111
|
+
* * `USE_PUBLIC_THREADS` (deprecated)
|
|
112
|
+
* * `CREATE_PUBLIC_THREADS`
|
|
113
|
+
* * `USE_PRIVATE_THREADS` (deprecated)
|
|
114
|
+
* * `CREATE_PRIVATE_THREADS`
|
|
115
|
+
* * `USE_EXTERNAL_STICKERS` (use stickers from different guilds)
|
|
116
|
+
* * `SEND_MESSAGES_IN_THREADS`
|
|
117
|
+
* * `START_EMBEDDED_ACTIVITIES`
|
|
118
|
+
* * `MODERATE_MEMBERS`
|
|
119
|
+
* * `VIEW_CREATOR_MONETIZATION_ANALYTICS`
|
|
120
|
+
* * `USE_SOUNDBOARD`
|
|
121
|
+
* * `CREATE_GUILD_EXPRESSIONS`
|
|
122
|
+
* * `CREATE_EVENTS`
|
|
123
|
+
* * `USE_EXTERNAL_SOUNDS`
|
|
124
|
+
* * `SEND_VOICE_MESSAGES`
|
|
125
|
+
* * `USE_CLYDE_AI`
|
|
126
|
+
* * `SET_VOICE_CHANNEL_STATUS`
|
|
127
|
+
* * `SEND_POLLS`
|
|
128
|
+
* * `USE_EXTERNAL_APPS`
|
|
129
|
+
* @type {Object<string, bigint>}
|
|
130
|
+
* @see {@link https://discord.com/developers/docs/topics/permissions#permissions-bitwise-permission-flags}
|
|
131
|
+
*/
|
|
132
|
+
Permissions.FLAGS = {
|
|
133
|
+
CREATE_INSTANT_INVITE: 1n << 0n,
|
|
134
|
+
KICK_MEMBERS: 1n << 1n,
|
|
135
|
+
BAN_MEMBERS: 1n << 2n,
|
|
136
|
+
ADMINISTRATOR: 1n << 3n,
|
|
137
|
+
MANAGE_CHANNELS: 1n << 4n,
|
|
138
|
+
MANAGE_GUILD: 1n << 5n,
|
|
139
|
+
ADD_REACTIONS: 1n << 6n,
|
|
140
|
+
VIEW_AUDIT_LOG: 1n << 7n,
|
|
141
|
+
PRIORITY_SPEAKER: 1n << 8n,
|
|
142
|
+
STREAM: 1n << 9n,
|
|
143
|
+
VIEW_CHANNEL: 1n << 10n,
|
|
144
|
+
SEND_MESSAGES: 1n << 11n,
|
|
145
|
+
SEND_TTS_MESSAGES: 1n << 12n,
|
|
146
|
+
MANAGE_MESSAGES: 1n << 13n,
|
|
147
|
+
EMBED_LINKS: 1n << 14n,
|
|
148
|
+
ATTACH_FILES: 1n << 15n,
|
|
149
|
+
READ_MESSAGE_HISTORY: 1n << 16n,
|
|
150
|
+
MENTION_EVERYONE: 1n << 17n,
|
|
151
|
+
USE_EXTERNAL_EMOJIS: 1n << 18n,
|
|
152
|
+
VIEW_GUILD_INSIGHTS: 1n << 19n,
|
|
153
|
+
CONNECT: 1n << 20n,
|
|
154
|
+
SPEAK: 1n << 21n,
|
|
155
|
+
MUTE_MEMBERS: 1n << 22n,
|
|
156
|
+
DEAFEN_MEMBERS: 1n << 23n,
|
|
157
|
+
MOVE_MEMBERS: 1n << 24n,
|
|
158
|
+
USE_VAD: 1n << 25n,
|
|
159
|
+
CHANGE_NICKNAME: 1n << 26n,
|
|
160
|
+
MANAGE_NICKNAMES: 1n << 27n,
|
|
161
|
+
MANAGE_ROLES: 1n << 28n,
|
|
162
|
+
MANAGE_WEBHOOKS: 1n << 29n,
|
|
163
|
+
MANAGE_EMOJIS_AND_STICKERS: 1n << 30n,
|
|
164
|
+
USE_APPLICATION_COMMANDS: 1n << 31n,
|
|
165
|
+
REQUEST_TO_SPEAK: 1n << 32n,
|
|
166
|
+
MANAGE_EVENTS: 1n << 33n,
|
|
167
|
+
MANAGE_THREADS: 1n << 34n,
|
|
168
|
+
CREATE_PUBLIC_THREADS: 1n << 35n,
|
|
169
|
+
CREATE_PRIVATE_THREADS: 1n << 36n,
|
|
170
|
+
USE_EXTERNAL_STICKERS: 1n << 37n,
|
|
171
|
+
SEND_MESSAGES_IN_THREADS: 1n << 38n,
|
|
172
|
+
START_EMBEDDED_ACTIVITIES: 1n << 39n,
|
|
173
|
+
MODERATE_MEMBERS: 1n << 40n,
|
|
174
|
+
VIEW_CREATOR_MONETIZATION_ANALYTICS: 1n << 41n,
|
|
175
|
+
USE_SOUNDBOARD: 1n << 42n,
|
|
176
|
+
CREATE_GUILD_EXPRESSIONS: 1n << 43n,
|
|
177
|
+
CREATE_EVENTS: 1n << 44n,
|
|
178
|
+
USE_EXTERNAL_SOUNDS: 1n << 45n,
|
|
179
|
+
SEND_VOICE_MESSAGES: 1n << 46n,
|
|
180
|
+
USE_CLYDE_AI: 1n << 47n,
|
|
181
|
+
SET_VOICE_CHANNEL_STATUS: 1n << 48n,
|
|
182
|
+
SEND_POLLS: 1n << 49n,
|
|
183
|
+
USE_EXTERNAL_APPS: 1n << 50n,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Bitfield representing every permission combined
|
|
188
|
+
* @type {bigint}
|
|
189
|
+
*/
|
|
190
|
+
Permissions.ALL = Object.values(Permissions.FLAGS).reduce(
|
|
191
|
+
(all, p) => all | p,
|
|
192
|
+
0n,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Bitfield representing the default permissions for users
|
|
197
|
+
* @type {bigint}
|
|
198
|
+
*/
|
|
199
|
+
Permissions.DEFAULT = BigInt(104324673);
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Bitfield representing the permissions required for moderators of stage channels
|
|
203
|
+
* @type {bigint}
|
|
204
|
+
*/
|
|
205
|
+
Permissions.STAGE_MODERATOR =
|
|
206
|
+
Permissions.FLAGS.MANAGE_CHANNELS |
|
|
207
|
+
Permissions.FLAGS.MUTE_MEMBERS |
|
|
208
|
+
Permissions.FLAGS.MOVE_MEMBERS;
|
|
209
|
+
|
|
210
|
+
Permissions.defaultBit = BigInt(0);
|
|
211
|
+
|
|
212
|
+
module.exports = Permissions;
|
|
@@ -81,7 +81,7 @@ class RestManager {
|
|
|
81
81
|
) {
|
|
82
82
|
const delay = rateLimit.reset - Date.now();
|
|
83
83
|
console.log(
|
|
84
|
-
`⏳ Route rate limit for ${routeKey}, waiting ${delay}ms`,
|
|
84
|
+
`⏳ Route rate limit for ${routeKey} (${endpoint}), waiting ${delay}ms`,
|
|
85
85
|
);
|
|
86
86
|
await this.sleep(delay);
|
|
87
87
|
}
|
|
@@ -129,14 +129,15 @@ class RestManager {
|
|
|
129
129
|
// Handle rate limiting
|
|
130
130
|
if (response.status === 429) {
|
|
131
131
|
const retryAfter =
|
|
132
|
-
parseInt(response.headers.get("retry-after")) * 1000;
|
|
132
|
+
parseInt(response.headers.get("retry-after")) * 1000 + 1000;
|
|
133
133
|
const isGlobal =
|
|
134
134
|
response.headers.get("x-ratelimit-global") === "true";
|
|
135
|
+
const routeKey = this.getRouteKey(endpoint, options.method || "GET");
|
|
135
136
|
|
|
136
137
|
console.log(
|
|
137
138
|
`🚫 Rate limited! ${
|
|
138
|
-
isGlobal ? "Global" :
|
|
139
|
-
} limit, retry after ${retryAfter}ms`,
|
|
139
|
+
isGlobal ? "Global" : `Route (${routeKey})`
|
|
140
|
+
} limit for ${endpoint}, retry after ${retryAfter}ms`,
|
|
140
141
|
);
|
|
141
142
|
|
|
142
143
|
if (isGlobal) {
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
const DiscordAPIError = require("../../classes/DiscordAPIError");
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Convert a color value to Discord's expected integer format
|
|
5
|
+
* @param {*} color - Color value (hex string, number, etc.)
|
|
6
|
+
* @returns {number|null} Integer color value or null
|
|
7
|
+
*/
|
|
8
|
+
function resolveColor(color) {
|
|
9
|
+
if (color === null || color === undefined) return null;
|
|
10
|
+
if (typeof color === "number") return color;
|
|
11
|
+
if (typeof color === "string") {
|
|
12
|
+
// Handle hex colors
|
|
13
|
+
if (color.startsWith("#")) {
|
|
14
|
+
return parseInt(color.slice(1), 16);
|
|
15
|
+
}
|
|
16
|
+
// Handle other string formats if needed
|
|
17
|
+
return parseInt(color, 16);
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
class WebhookClient {
|
|
4
23
|
/**
|
|
5
24
|
* Create a new WebhookClient
|
|
@@ -186,7 +205,10 @@ class WebhookClient {
|
|
|
186
205
|
payload.avatar_url = options.avatarURL;
|
|
187
206
|
}
|
|
188
207
|
if (options.embeds) {
|
|
189
|
-
payload.embeds = options.embeds
|
|
208
|
+
payload.embeds = options.embeds.map((embed) => ({
|
|
209
|
+
...embed,
|
|
210
|
+
color: resolveColor(embed.color),
|
|
211
|
+
}));
|
|
190
212
|
}
|
|
191
213
|
if (options.tts !== undefined) {
|
|
192
214
|
payload.tts = options.tts;
|
|
@@ -212,11 +234,11 @@ class WebhookClient {
|
|
|
212
234
|
description: data.description || null,
|
|
213
235
|
url: data.url || null,
|
|
214
236
|
timestamp: data.timestamp || null,
|
|
215
|
-
color: data.color
|
|
237
|
+
color: resolveColor(data.color),
|
|
216
238
|
footer: data.footer
|
|
217
239
|
? {
|
|
218
240
|
text: data.footer.text,
|
|
219
|
-
icon_url: data.footer.iconURL,
|
|
241
|
+
icon_url: data.footer.iconURL || data.footer.icon_url,
|
|
220
242
|
}
|
|
221
243
|
: null,
|
|
222
244
|
image: data.image ? { url: data.image } : null,
|
|
@@ -225,7 +247,7 @@ class WebhookClient {
|
|
|
225
247
|
? {
|
|
226
248
|
name: data.author.name,
|
|
227
249
|
url: data.author.url,
|
|
228
|
-
icon_url: data.author.iconURL,
|
|
250
|
+
icon_url: data.author.iconURL || data.author.icon_url,
|
|
229
251
|
}
|
|
230
252
|
: null,
|
|
231
253
|
fields: data.fields || [],
|
package/src/index.js
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
const Client = require("./classes/Client");
|
|
21
21
|
const WebhookClient = require("./connection/webhook/WebhookClient");
|
|
22
|
+
const Permissions = require("./classes/Permissions");
|
|
23
|
+
const BitField = require("./classes/BitField");
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Main package exports
|
|
@@ -38,4 +40,18 @@ module.exports = {
|
|
|
38
40
|
* @see {@link WebhookClient}
|
|
39
41
|
*/
|
|
40
42
|
WebhookClient,
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Discord permission flags and utilities
|
|
46
|
+
* @type {Permissions}
|
|
47
|
+
* @see {@link Permissions}
|
|
48
|
+
*/
|
|
49
|
+
Permissions,
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Base class for handling bitfields
|
|
53
|
+
* @type {BitField}
|
|
54
|
+
* @see {@link BitField}
|
|
55
|
+
*/
|
|
56
|
+
BitField,
|
|
41
57
|
};
|