djs-selfbot-v13 3.7.15 → 3.7.17

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": "djs-selfbot-v13",
3
- "version": "3.7.15",
3
+ "version": "3.7.17",
4
4
  "description": "An unofficial discord.js fork for creating selfbots",
5
5
  "main": "./src/index.js",
6
6
  "types": "./typings/index.d.ts",
@@ -16,9 +16,7 @@ class APIRequest {
16
16
  this.route = options.route;
17
17
  this.options = options;
18
18
  this.retries = 0;
19
-
20
19
  this.fullUserAgent = this.client.options.http.headers['User-Agent'];
21
-
22
20
  this.client.options.ws.properties.browser_user_agent = this.fullUserAgent;
23
21
 
24
22
  let queryString = '';
@@ -223,19 +223,8 @@ class BaseGuildVoiceChannel extends GuildChannel {
223
223
  return this.edit({ videoQualityMode }, reason);
224
224
  }
225
225
 
226
- // These are here only for documentation purposes - they are implemented by TextBasedChannel
227
- /* eslint-disable no-empty-function */
228
- get lastMessage() {}
229
- send() {}
230
- sendTyping() {}
231
- createMessageCollector() {}
232
- awaitMessages() {}
233
- fetchWebhooks() {}
234
- createWebhook() {}
235
- setRateLimitPerUser() {}
236
- setNSFW() {}
237
226
  }
238
227
 
239
228
  TextBasedChannel.applyToClass(BaseGuildVoiceChannel, true, ['lastPinAt']);
240
229
 
241
- module.exports = BaseGuildVoiceChannel;
230
+ module.exports = BaseGuildVoiceChannel;
@@ -41,20 +41,44 @@ class ClientPresence extends Presence {
41
41
  since: typeof since === 'number' && !Number.isNaN(since) ? this.since : 0,
42
42
  status: status ?? this.status,
43
43
  };
44
+
45
+ // Récupère le custom status actuellement en cache pour ne pas l'écraser
46
+ // lors d'un setActivity / setStatus qui ne touche pas au custom status
47
+ const existingCustom = this.activities?.find(a =>
48
+ CustomStatusActivityTypes.includes(a.type),
49
+ );
50
+
44
51
  if (activities?.length) {
52
+ let hasCustom = false;
45
53
  for (const [i, activity] of activities.entries()) {
46
54
  if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string');
47
55
 
48
56
  activity.type ??= ActivityTypes.PLAYING;
49
57
  if (typeof activity.type === 'string') activity.type = ActivityTypes[activity.type];
50
58
 
51
- if (CustomStatusActivityTypes.includes(activity.type) && !activity.state) {
52
- activity.state = activity.name;
53
- activity.name = 'Custom Status';
59
+ if (CustomStatusActivityTypes.includes(activity.type)) {
60
+ hasCustom = true;
61
+ if (!activity.state) {
62
+ activity.state = activity.name;
63
+ activity.name = 'Custom Status';
64
+ }
54
65
  }
55
66
 
56
67
  data.activities.push(activity);
57
68
  }
69
+
70
+ // Si le tableau d'activités passé ne contient pas de custom status,
71
+ // réinjecte celui du cache pour ne pas le perdre
72
+ if (!hasCustom && existingCustom) {
73
+ data.activities.unshift({
74
+ type: typeof existingCustom.type === 'string'
75
+ ? ActivityTypes[existingCustom.type]
76
+ : existingCustom.type,
77
+ name: existingCustom.name ?? 'Custom Status',
78
+ state: existingCustom.state ?? null,
79
+ emoji: existingCustom.emoji ?? null,
80
+ });
81
+ }
58
82
  } else if (!activities && (status || afk || since) && this.activities.length) {
59
83
  data.activities.push(
60
84
  ...this.activities.map(a => {
@@ -74,4 +98,4 @@ module.exports = ClientPresence;
74
98
  /**
75
99
  * @external APIPresence
76
100
  * @see {@link https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields}
77
- */
101
+ */
@@ -267,6 +267,68 @@ class ClientUser extends User {
267
267
  return this.setPresence({ afk, shardId });
268
268
  }
269
269
 
270
+ /**
271
+ * Sets the custom status of the client user.
272
+ * Updates both the Gateway (local real-time display) and the REST API (account persistence).
273
+ * @param {CustomStatus|CustomStatusOptions|string|null} options
274
+ * A `CustomStatus` instance, an options object, a plain string for the state, or `null` to clear.
275
+ * @param {string} [options.state] Text displayed as the status
276
+ * @param {EmojiIdentifierResolvable} [options.emoji] Emoji shown next to the text
277
+ * @param {string} [options.expiresAt] ISO8601 date at which Discord auto-clears the status
278
+ * @param {number|number[]} [options.shardId] Shard(s) to broadcast the Gateway update on
279
+ * @returns {Promise<ClientPresence>}
280
+ * @example
281
+ * // With text + unicode emoji
282
+ * await client.user.setCustomStatus({ state: 'Coding...', emoji: '💻' });
283
+ * @example
284
+ * // Plain string shorthand
285
+ * await client.user.setCustomStatus('Taking a break');
286
+ * @example
287
+ * // Clear the custom status
288
+ * await client.user.setCustomStatus(null);
289
+ */
290
+ async setCustomStatus(options, shardId) {
291
+ const { CustomStatus } = require('../structures/Presence');
292
+
293
+ // ── 1. Normalise l'entrée ─────────────────────────────────────────────
294
+ let activity = null; // null = effacer
295
+ let restPayload = null;
296
+
297
+ if (options !== null && options !== undefined) {
298
+ if (typeof options === 'string') options = { state: options };
299
+
300
+ // Supporte un objet CustomStatus existant (déjà construit par l'utilisateur)
301
+ const cs = options instanceof CustomStatus
302
+ ? options
303
+ : new CustomStatus(this.client, {
304
+ state: options.state ?? null,
305
+ emoji: options.emoji ? { name: options.emoji } : undefined,
306
+ });
307
+
308
+ activity = cs.toJSON(); // { name, type, state, emoji }
309
+
310
+ restPayload = {
311
+ text: cs.state ?? null,
312
+ emoji_name: cs.emoji?.name ?? null,
313
+ emoji_id: cs.emoji?.id ?? null,
314
+ expires_at: options.expiresAt ?? null,
315
+ };
316
+ }
317
+
318
+ // ── 2. Gateway — visible localement en temps réel ────────────────────
319
+ const presenceActivities = activity ? [activity] : [];
320
+ const presence = this.setPresence({ activities: presenceActivities, shardId });
321
+
322
+ // ── 3. REST — persistance sur le compte Discord ───────────────────────
323
+ await this.client.api.users('@me').settings.patch({ data: { custom_status: restPayload } })
324
+ .catch(err => {
325
+ // Non bloquant : on ne veut pas casser setPresence si l'endpoint échoue
326
+ this.client.emit('warn', `[setCustomStatus] REST patch failed: ${err?.message ?? err}`);
327
+ });
328
+
329
+ return presence;
330
+ }
331
+
270
332
  /**
271
333
  * Sets the banner of the logged in client.
272
334
  * @param {?(BufferResolvable|Base64Resolvable)} banner The new banner
@@ -688,4 +750,4 @@ class ClientUser extends User {
688
750
  }
689
751
  }
690
752
 
691
- module.exports = ClientUser;
753
+ module.exports = ClientUser;
@@ -1752,6 +1752,49 @@ class Guild extends AnonymousGuild {
1752
1752
  return data;
1753
1753
  }
1754
1754
 
1755
+ /**
1756
+ * Get the number of members that would be pruned
1757
+ * @param {number} [days=7] Number of days of inactivity
1758
+ * @param {string[]} [includeRoles=[]] Role IDs to include in the prune
1759
+ * @returns {Promise<number>} The number of members that would be pruned
1760
+ */
1761
+ async pruneCount(days = 7, includeRoles = []) {
1762
+ const query = { days };
1763
+
1764
+ if (includeRoles.length > 0) {
1765
+ query.include_roles = includeRoles.join('&include_roles=');
1766
+ }
1767
+
1768
+ const params = new URLSearchParams({ days: days.toString() });
1769
+ if (includeRoles.length > 0) {
1770
+ for (const roleId of includeRoles) {
1771
+ params.append('include_roles', roleId);
1772
+ }
1773
+ }
1774
+
1775
+ const data = await this.client.api.guilds(this.id)['prune/v2'].get({ query: Object.fromEntries(params) });
1776
+ return data.pruned;
1777
+ }
1778
+
1779
+ /**
1780
+ * Prune inactive members from the guild
1781
+ * @param {number} [days=7] Number of days of inactivity
1782
+ * @param {string[]} [includeRoles=[]] Role IDs to include in the prune
1783
+ * @param {boolean} [computePruneCount=false] Whether to return the number of pruned members
1784
+ * @returns {Promise<number|null>} The number of pruned members, or null if computePruneCount is false
1785
+ */
1786
+ async pruneMembers(days = 7, includeRoles = [], computePruneCount = false) {
1787
+ const data = await this.client.api.guilds(this.id).prune.post({
1788
+ data: {
1789
+ days,
1790
+ compute_prune_count: computePruneCount,
1791
+ include_roles: includeRoles
1792
+ }
1793
+ });
1794
+ return data.pruned ?? null;
1795
+ }
1796
+
1797
+
1755
1798
  /**
1756
1799
  * Creates a collection of this guild's roles, sorted by their position and ids.
1757
1800
  * @returns {Collection<Snowflake, Role>}
@@ -465,6 +465,7 @@ class User extends Base {
465
465
  this.globalName === user.global_name &&
466
466
  this.avatar === user.avatar &&
467
467
  this.flags?.bitfield === user.public_flags &&
468
+ ('bio' in data ? this.bio = data.bio : true)
468
469
  ('banner' in user ? this.banner === user.banner : true) &&
469
470
  ('accent_color' in user ? this.accentColor === user.accent_color : true) &&
470
471
  ('avatar_decoration_data' in user
@@ -1716,6 +1716,8 @@ export class Guild extends AnonymousGuild {
1716
1716
  rulesChannel?: GuildTextChannelResolvable,
1717
1717
  reason?: string,
1718
1718
  ): Promise<this>;
1719
+ public pruneMembers(days?: number, includeRoles?: string[], computePruneCount?: boolean): Promise<number | null>;
1720
+ public pruneCount(days?: number, includeRoles?: string[]): Promise<number>;
1719
1721
  public topEmojis(): Promise<Collection<number, GuildEmoji>>;
1720
1722
  public setVanityCode(code?: string): Promise<this>;
1721
1723
  public mute(options?: GuildMuteOptions): Promise<any>;
@@ -3994,6 +3996,7 @@ export class User extends PartialTextBasedChannel(Base) {
3994
3996
  public readonly avatarDecoration: string | null;
3995
3997
  public avatarDecorationData: AvatarDecorationData | null;
3996
3998
  public banner: string | null | undefined;
3999
+ public bio?: string | null;
3997
4000
  public bannerColor: string | null | undefined;
3998
4001
  public bot: boolean;
3999
4002
  public readonly createdAt: Date;