discord-self-lite 0.1.5 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discord-self-lite",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Lightweight Discord selfbot library",
5
5
  "keywords": [
6
6
  "discord",
@@ -90,7 +90,13 @@ class BitField {
90
90
  return bit
91
91
  .map((p) => this.resolve(p))
92
92
  .reduce((prev, p) => prev | p, BitField.defaultBit);
93
- if (typeof bit === "string") return this.FLAGS[bit];
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);
94
100
  throw new TypeError("BitField.resolve: Invalid bitfield");
95
101
  }
96
102
  }
@@ -3,6 +3,18 @@
3
3
  */
4
4
  const Permissions = require("./Permissions");
5
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
+
6
18
  class Channel {
7
19
  /**
8
20
  * Create a new Channel instance
@@ -170,7 +182,7 @@ class Channel {
170
182
  * @returns {Permissions} Permissions bitfield for this member in this channel
171
183
  */
172
184
  permissionsFor(member) {
173
- if (!member) return new Permissions(BigInt(0));
185
+ if (!member?.permissions) return new Permissions(toBigInt(0));
174
186
 
175
187
  // Start with the member's base guild permissions
176
188
  let permissions = member.permissions.bitfield;
@@ -193,8 +205,8 @@ class Channel {
193
205
  memberRoles.includes(overwrite.id) ||
194
206
  overwrite.id === this.data.guild_id
195
207
  ) {
196
- permissions &= ~BigInt(overwrite.deny || 0);
197
- permissions |= BigInt(overwrite.allow || 0);
208
+ permissions &= ~toBigInt(overwrite.deny || 0);
209
+ permissions |= toBigInt(overwrite.allow || 0);
198
210
  }
199
211
  }
200
212
  }
@@ -204,13 +216,63 @@ class Channel {
204
216
  (ow) => ow.type === 1 && ow.id === member.id,
205
217
  );
206
218
  if (memberOverwrite) {
207
- permissions &= ~BigInt(memberOverwrite.deny || 0);
208
- permissions |= BigInt(memberOverwrite.allow || 0);
219
+ permissions &= ~toBigInt(memberOverwrite.deny || 0);
220
+ permissions |= toBigInt(memberOverwrite.allow || 0);
209
221
  }
210
222
  }
211
223
 
212
224
  return new Permissions(permissions);
213
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
+ }
214
276
  }
215
277
 
216
278
  module.exports = Channel;
@@ -3,6 +3,18 @@
3
3
  */
4
4
  const Permissions = require("./Permissions");
5
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
+
6
18
  class GuildMember {
7
19
  /**
8
20
  * Create a new GuildMember instance
@@ -58,7 +70,7 @@ class GuildMember {
58
70
  if (this._permissions) return this._permissions;
59
71
 
60
72
  // Calculate permissions based on roles
61
- let permissions = BigInt(0);
73
+ let permissions = 0n;
62
74
 
63
75
  // If member is the guild owner, they have all permissions
64
76
  if (this.id === this.guild.ownerId) {
@@ -68,15 +80,15 @@ class GuildMember {
68
80
  const everyoneRole = this.guild.roles?.find(
69
81
  (role) => role.id === this.guild.id,
70
82
  );
71
- if (everyoneRole) {
72
- permissions |= BigInt(everyoneRole.permissions || 0);
83
+ if (everyoneRole && everyoneRole.permissions != null) {
84
+ permissions |= toBigInt(everyoneRole.permissions);
73
85
  }
74
86
 
75
87
  // Add permissions from member's roles
76
88
  for (const roleId of this.roles || []) {
77
89
  const role = this.guild.roles?.find((r) => r.id === roleId);
78
- if (role) {
79
- permissions |= BigInt(role.permissions || 0);
90
+ if (role && role.permissions != null) {
91
+ permissions |= toBigInt(role.permissions);
80
92
  }
81
93
  }
82
94
  }
@@ -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" : "Route"
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 || null,
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 || [],