discord.js 15.0.0-pr-11005.1765454364-f3f6d34e7 → 15.0.0-pr-10758.1765463096-d081e1706

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,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "discord.js",
4
- "version": "15.0.0-pr-11005.1765454364-f3f6d34e7",
4
+ "version": "15.0.0-pr-10758.1765463096-d081e1706",
5
5
  "description": "A powerful library for interacting with the Discord API",
6
6
  "main": "./src/index.js",
7
7
  "types": "./typings/index.d.ts",
@@ -55,35 +55,33 @@
55
55
  "dependencies": {
56
56
  "@sapphire/snowflake": "3.5.5",
57
57
  "@vladfrangu/async_event_emitter": "^2.4.7",
58
- "discord-api-types": "^0.38.31",
58
+ "discord-api-types": "^0.38.36",
59
59
  "fast-deep-equal": "3.1.3",
60
60
  "lodash.snakecase": "4.1.1",
61
61
  "magic-bytes.js": "^1.12.1",
62
62
  "tslib": "^2.8.1",
63
63
  "undici": "7.16.0",
64
- "@discordjs/formatters": "1.0.0-pr-11005.1765454364-f3f6d34e7",
65
- "@discordjs/builders": "2.0.0-pr-11005.1765454364-f3f6d34e7",
66
- "@discordjs/collection": "3.0.0-pr-11005.1765454364-f3f6d34e7",
67
- "@discordjs/rest": "3.0.0-pr-11005.1765454364-f3f6d34e7",
68
- "@discordjs/util": "2.0.0-pr-11005.1765454364-f3f6d34e7",
69
- "@discordjs/ws": "3.0.0-pr-11005.1765454364-f3f6d34e7"
64
+ "@discordjs/builders": "2.0.0-pr-10758.1765463096-d081e1706",
65
+ "@discordjs/collection": "3.0.0-pr-10758.1765463096-d081e1706",
66
+ "@discordjs/formatters": "1.0.0-pr-10758.1765463096-d081e1706",
67
+ "@discordjs/rest": "3.0.0-pr-10758.1765463096-d081e1706",
68
+ "@discordjs/ws": "3.0.0-pr-10758.1765463096-d081e1706",
69
+ "@discordjs/util": "2.0.0-pr-10758.1765463096-d081e1706"
70
70
  },
71
71
  "devDependencies": {
72
- "@favware/cliff-jumper": "^4.1.0",
73
- "@types/node": "^22.18.13",
72
+ "@favware/cliff-jumper": "^6.0.0",
73
+ "@types/node": "^22.19.2",
74
74
  "cross-env": "^10.1.0",
75
- "eslint": "^9.38.0",
75
+ "eslint": "^9.39.1",
76
76
  "eslint-config-neon": "^0.2.9",
77
77
  "eslint-formatter-compact": "^9.0.1",
78
78
  "eslint-formatter-pretty": "^7.0.0",
79
- "eslint-plugin-import": "^2.32.0",
80
- "eslint-plugin-jsdoc": "^54.7.0",
81
- "prettier": "^3.6.2",
79
+ "prettier": "^3.7.4",
82
80
  "tsd": "^0.33.0",
83
- "turbo": "^2.5.8",
81
+ "turbo": "^2.6.3",
84
82
  "typescript": "~5.9.3",
85
- "@discordjs/api-extractor": "7.52.7",
86
83
  "@discordjs/docgen": "0.12.1",
84
+ "@discordjs/api-extractor": "7.52.7",
87
85
  "@discordjs/scripts": "0.1.0"
88
86
  },
89
87
  "engines": {
@@ -389,15 +389,6 @@ class Client extends AsyncEventEmitter {
389
389
  );
390
390
  this.ws.on(WebSocketShardEvents.Dispatch, this._handlePacket.bind(this));
391
391
 
392
- this.ws.on(WebSocketShardEvents.Ready, async data => {
393
- for (const guild of data.guilds) {
394
- this.expectedGuilds.add(guild.id);
395
- }
396
-
397
- this.status = Status.WaitingForGuilds;
398
- await this._checkReady();
399
- });
400
-
401
392
  this.ws.on(WebSocketShardEvents.HeartbeatComplete, ({ heartbeatAt, latency }, shardId) => {
402
393
  this.emit(Events.Debug, `[WS => Shard ${shardId}] Heartbeat acknowledged, latency of ${latency}ms.`);
403
394
  this.lastPingTimestamps.set(shardId, heartbeatAt);
@@ -427,7 +418,9 @@ class Client extends AsyncEventEmitter {
427
418
  PacketHandlers[packet.t](this, packet, shardId);
428
419
  }
429
420
 
430
- if (this.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(packet.t)) {
421
+ if (packet.t === GatewayDispatchEvents.Ready) {
422
+ await this._checkReady();
423
+ } else if (this.status === Status.WaitingForGuilds && WaitingForGuildEvents.includes(packet.t)) {
431
424
  this.expectedGuilds.delete(packet.d.id);
432
425
  await this._checkReady();
433
426
  }
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { ClientApplication } = require('../../../structures/ClientApplication.js');
4
+ const { Status } = require('../../../util/Status.js');
4
5
 
5
6
  let ClientUser;
6
7
 
@@ -14,6 +15,7 @@ module.exports = (client, { d: data }, shardId) => {
14
15
  }
15
16
 
16
17
  for (const guild of data.guilds) {
18
+ client.expectedGuilds.add(guild.id);
17
19
  guild.shardId = shardId;
18
20
  client.guilds._add(guild);
19
21
  }
@@ -23,4 +25,6 @@ module.exports = (client, { d: data }, shardId) => {
23
25
  } else {
24
26
  client.application = new ClientApplication(client, data.application);
25
27
  }
28
+
29
+ client.status = Status.WaitingForGuilds;
26
30
  };
@@ -12,15 +12,19 @@ const { Messages } = require('./Messages.js');
12
12
  * @ignore
13
13
  */
14
14
  function makeDiscordjsError(Base) {
15
- return class DiscordjsError extends Base {
15
+ return class extends Base {
16
+ static {
17
+ Object.defineProperty(this, 'name', { value: `Discordjs${Base.name}` });
18
+ }
19
+
16
20
  constructor(code, ...args) {
17
21
  super(message(code, args));
18
22
  this.code = code;
19
- Error.captureStackTrace?.(this, DiscordjsError);
23
+ Error.captureStackTrace(this, this.constructor);
20
24
  }
21
25
 
22
26
  get name() {
23
- return `${super.name} [${this.code}]`;
27
+ return `${this.constructor.name} [${this.code}]`;
24
28
  }
25
29
  };
26
30
  }
@@ -83,7 +83,7 @@
83
83
  *
84
84
  * @property {'EmojiType'} EmojiType
85
85
  * @property {'EmojiManaged'} EmojiManaged
86
- * @property {'MissingManageGuildExpressionsPermission'} MissingManageGuildExpressionsPermission
86
+ * @property {'MissingGuildExpressionsPermission'} MissingGuildExpressionsPermission
87
87
  *
88
88
  * @property {'NotGuildSoundboardSound'} NotGuildSoundboardSound
89
89
  * @property {'NotGuildSticker'} NotGuildSticker
@@ -217,7 +217,7 @@ const keys = [
217
217
 
218
218
  'EmojiType',
219
219
  'EmojiManaged',
220
- 'MissingManageGuildExpressionsPermission',
220
+ 'MissingGuildExpressionsPermission',
221
221
 
222
222
  'NotGuildSoundboardSound',
223
223
  'NotGuildSticker',
@@ -88,8 +88,8 @@ const Messages = {
88
88
 
89
89
  [ErrorCodes.EmojiType]: 'Emoji must be a string or GuildEmoji/ReactionEmoji',
90
90
  [ErrorCodes.EmojiManaged]: 'Emoji is managed and has no Author.',
91
- [ErrorCodes.MissingManageGuildExpressionsPermission]: guild =>
92
- `Client must have Manage Guild Expressions permission in guild ${guild} to see emoji authors.`,
91
+ [ErrorCodes.MissingGuildExpressionsPermission]: guild =>
92
+ `Client must have Create Guild Expressions or Manage Guild Expressions permission in guild ${guild} to see emoji authors.`,
93
93
 
94
94
  [ErrorCodes.NotGuildSoundboardSound]: action =>
95
95
  `Soundboard sound is a default (non-guild) soundboard sound and can't be ${action}.`,
package/src/index.js CHANGED
@@ -111,7 +111,6 @@ exports.ApplicationEmoji = require('./structures/ApplicationEmoji.js').Applicati
111
111
  exports.ApplicationRoleConnectionMetadata =
112
112
  require('./structures/ApplicationRoleConnectionMetadata.js').ApplicationRoleConnectionMetadata;
113
113
  exports.Attachment = require('./structures/Attachment.js').Attachment;
114
- exports.AttachmentBuilder = require('./structures/AttachmentBuilder.js').AttachmentBuilder;
115
114
  exports.AutocompleteInteraction = require('./structures/AutocompleteInteraction.js').AutocompleteInteraction;
116
115
  exports.AutoModerationActionExecution =
117
116
  require('./structures/AutoModerationActionExecution.js').AutoModerationActionExecution;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const process = require('node:process');
4
- const { lazy } = require('@discordjs/util');
4
+ const { lazy, isFileBodyEncodable, isJSONEncodable } = require('@discordjs/util');
5
5
  const { Routes } = require('discord-api-types/v10');
6
6
  const { BaseChannel } = require('../structures/BaseChannel.js');
7
7
  const { MessagePayload } = require('../structures/MessagePayload.js');
@@ -147,7 +147,7 @@ class ChannelManager extends CachedManager {
147
147
  * Creates a message in a channel.
148
148
  *
149
149
  * @param {TextChannelResolvable} channel The channel to send the message to
150
- * @param {string|MessagePayload|MessageCreateOptions} options The options to provide
150
+ * @param {string|MessagePayload|MessageCreateOptions|JSONEncodable<RESTPostAPIChannelMessageJSONBody>|FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>} options The options to provide
151
151
  * @returns {Promise<Message>}
152
152
  * @example
153
153
  * // Send a basic message
@@ -174,18 +174,21 @@ class ChannelManager extends CachedManager {
174
174
  * .catch(console.error);
175
175
  */
176
176
  async createMessage(channel, options) {
177
- let messagePayload;
177
+ let payload;
178
178
 
179
179
  if (options instanceof MessagePayload) {
180
- messagePayload = options.resolveBody();
180
+ payload = await options.resolveBody().resolveFiles();
181
+ } else if (isFileBodyEncodable(options)) {
182
+ payload = options.toFileBody();
183
+ } else if (isJSONEncodable(options)) {
184
+ payload = { body: options.toJSON() };
181
185
  } else {
182
- messagePayload = MessagePayload.create(this, options).resolveBody();
186
+ payload = await MessagePayload.create(this, options).resolveBody().resolveFiles();
183
187
  }
184
188
 
185
189
  const resolvedChannelId = this.resolveId(channel);
186
190
  const resolvedChannel = this.resolve(channel);
187
- const { body, files } = await messagePayload.resolveFiles();
188
- const data = await this.client.rest.post(Routes.channelMessages(resolvedChannelId), { body, files });
191
+ const data = await this.client.rest.post(Routes.channelMessages(resolvedChannelId), payload);
189
192
 
190
193
  return resolvedChannel?.messages._add(data) ?? new (getMessage())(this.client, data);
191
194
  }
@@ -251,8 +251,8 @@ class GuildEmojiManager extends CachedManager {
251
251
 
252
252
  const { me } = this.guild.members;
253
253
  if (!me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
254
- if (!me.permissions.has(PermissionFlagsBits.ManageGuildExpressions)) {
255
- throw new DiscordjsError(ErrorCodes.MissingManageGuildExpressionsPermission, this.guild);
254
+ if (!me.permissions.any(PermissionFlagsBits.CreateGuildExpressions | PermissionFlagsBits.ManageGuildExpressions)) {
255
+ throw new DiscordjsError(ErrorCodes.MissingGuildExpressionsPermission, this.guild);
256
256
  }
257
257
 
258
258
  const data = await this.client.rest.get(Routes.guildEmoji(this.guild.id, resolvedEmoji.id));
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { Collection } = require('@discordjs/collection');
4
4
  const { makeURLSearchParams } = require('@discordjs/rest');
5
+ const { isFileBodyEncodable, isJSONEncodable } = require('@discordjs/util');
5
6
  const { Routes } = require('discord-api-types/v10');
6
7
  const { DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
7
8
  const { Message } = require('../structures/Message.js');
@@ -223,21 +224,27 @@ class MessageManager extends CachedManager {
223
224
  * Edits a message, even if it's not cached.
224
225
  *
225
226
  * @param {MessageResolvable} message The message to edit
226
- * @param {string|MessageEditOptions|MessagePayload} options The options to edit the message
227
+ * @param {string|MessageEditOptions|MessagePayload|FileBodyEncodable<RESTPatchAPIChannelMessageJSONBody>|JSONEncodable<RESTPatchAPIChannelMessageJSONBody>} options The options to edit the message
227
228
  * @returns {Promise<Message>}
228
229
  */
229
230
  async edit(message, options) {
230
231
  const messageId = this.resolveId(message);
231
232
  if (!messageId) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
232
233
 
233
- const { body, files } = await (
234
- options instanceof MessagePayload
235
- ? options
236
- : MessagePayload.create(message instanceof Message ? message : this, options)
237
- )
238
- .resolveBody()
239
- .resolveFiles();
240
- const data = await this.client.rest.patch(Routes.channelMessage(this.channel.id, messageId), { body, files });
234
+ let payload;
235
+ if (options instanceof MessagePayload) {
236
+ payload = await options.resolveBody().resolveFiles();
237
+ } else if (isFileBodyEncodable(options)) {
238
+ payload = options.toFileBody();
239
+ } else if (isJSONEncodable(options)) {
240
+ payload = { body: options.toJSON() };
241
+ } else {
242
+ payload = await MessagePayload.create(message instanceof Message ? message : this, options)
243
+ .resolveBody()
244
+ .resolveFiles();
245
+ }
246
+
247
+ const data = await this.client.rest.patch(Routes.channelMessage(this.channel.id, messageId), payload);
241
248
 
242
249
  const existing = this.cache.get(messageId);
243
250
  if (existing) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { embedLength } = require('@discordjs/builders');
3
+ const { embedLength } = require('@discordjs/util');
4
4
  const isEqual = require('fast-deep-equal');
5
5
 
6
6
  /**
@@ -641,7 +641,7 @@ class Guild extends AnonymousGuild {
641
641
  }
642
642
 
643
643
  /**
644
- * The maximum bitrate available for this guild
644
+ * The maximum bitrate available for a voice channel in this guild
645
645
  *
646
646
  * @type {number}
647
647
  * @readonly
@@ -663,6 +663,16 @@ class Guild extends AnonymousGuild {
663
663
  }
664
664
  }
665
665
 
666
+ /**
667
+ * The maximum bitrate available for a stage channel in this guild
668
+ *
669
+ * @type {number}
670
+ * @readonly
671
+ */
672
+ get maximumStageBitrate() {
673
+ return 64_000;
674
+ }
675
+
666
676
  /**
667
677
  * Fetches a collection of integrations to this guild.
668
678
  * Resolves with a collection mapping integrations by their ids.
@@ -192,7 +192,7 @@ class GuildInvite extends BaseInvite {
192
192
  if (!guild.members.me) throw new DiscordjsError(ErrorCodes.GuildUncachedMe);
193
193
  return Boolean(
194
194
  this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageChannels, false) ||
195
- guild.members.me.permissions.has(PermissionFlagsBits.ManageGuild),
195
+ guild.members.me.permissions.has(PermissionFlagsBits.ManageGuild),
196
196
  );
197
197
  }
198
198
 
@@ -725,8 +725,8 @@ class Message extends Base {
725
725
  get editable() {
726
726
  const precheck = Boolean(
727
727
  this.author.id === this.client.user.id &&
728
- (!this.guild || this.channel?.viewable) &&
729
- this.reference?.type !== MessageReferenceType.Forward,
728
+ (!this.guild || this.channel?.viewable) &&
729
+ this.reference?.type !== MessageReferenceType.Forward,
730
730
  );
731
731
 
732
732
  // Regardless of permissions thread messages cannot be edited if
@@ -837,19 +837,19 @@ class Message extends Base {
837
837
  const { channel } = this;
838
838
  return Boolean(
839
839
  channel?.type === ChannelType.GuildAnnouncement &&
840
- !this.flags.has(MessageFlags.Crossposted) &&
841
- this.reference?.type !== MessageReferenceType.Forward &&
842
- this.type === MessageType.Default &&
843
- !this.poll &&
844
- channel.viewable &&
845
- channel.permissionsFor(this.client.user)?.has(bitfield, false),
840
+ !this.flags.has(MessageFlags.Crossposted) &&
841
+ this.reference?.type !== MessageReferenceType.Forward &&
842
+ this.type === MessageType.Default &&
843
+ !this.poll &&
844
+ channel.viewable &&
845
+ channel.permissionsFor(this.client.user)?.has(bitfield, false),
846
846
  );
847
847
  }
848
848
 
849
849
  /**
850
850
  * Edits the content of the message.
851
851
  *
852
- * @param {string|MessagePayload|MessageEditOptions} options The options to provide
852
+ * @param {string|MessageEditOptions|MessagePayload|FileBodyEncodable<RESTPatchAPIChannelMessageJSONBody>|JSONEncodable<RESTPatchAPIChannelMessageJSONBody>} options The options to provide
853
853
  * @returns {Promise<Message>}
854
854
  * @example
855
855
  * // Update the content of a message
@@ -197,10 +197,13 @@ class MessagePayload {
197
197
  waveform: file.waveform,
198
198
  duration_secs: file.duration,
199
199
  }));
200
+
201
+ // Only passable during edits
200
202
  if (Array.isArray(this.options.attachments)) {
201
- this.options.attachments.push(...(attachments ?? []));
202
- } else {
203
- this.options.attachments = attachments;
203
+ attachments.push(
204
+ // Note how we don't check for file body encodable, since we aren't expecting file data here
205
+ ...this.options.attachments.map(attachment => (isJSONEncodable(attachment) ? attachment.toJSON() : attachment)),
206
+ );
204
207
  }
205
208
 
206
209
  let poll;
@@ -237,7 +240,7 @@ class MessagePayload {
237
240
  : allowedMentions,
238
241
  flags,
239
242
  message_reference,
240
- attachments: this.options.attachments,
243
+ attachments,
241
244
  sticker_ids: this.options.stickers?.map(sticker => sticker.id ?? sticker),
242
245
  thread_name: threadName,
243
246
  applied_tags: appliedTags,
@@ -88,7 +88,7 @@ class TextBasedChannel {
88
88
  * @property {Array<(EmbedBuilder|Embed|APIEmbed)>} [embeds] The embeds for the message
89
89
  * @property {MessageMentionOptions} [allowedMentions] Which mentions should be parsed from the message content
90
90
  * (see {@link https://discord.com/developers/docs/resources/message#allowed-mentions-object here} for more details)
91
- * @property {Array<(AttachmentBuilder|Attachment|AttachmentPayload|BufferResolvable)>} [files]
91
+ * @property {Array<(Attachment|AttachmentPayload|BufferResolvable|FileBodyEncodable<APIAttachment>|Stream)>} [files]
92
92
  * The files to send with the message.
93
93
  * @property {Array<(ActionRowBuilder|MessageTopLevelComponent|APIMessageTopLevelComponent)>} [components]
94
94
  * Action rows containing interactive components for the message (buttons, select menus) and other
@@ -156,7 +156,7 @@ class TextBasedChannel {
156
156
  /**
157
157
  * Sends a message to this channel.
158
158
  *
159
- * @param {string|MessagePayload|MessageCreateOptions} options The options to provide
159
+ * @param {string|MessagePayload|MessageCreateOptions|JSONEncodable<RESTPostAPIChannelMessageJSONBody>|FileBodyEncodable<RESTPostAPIChannelMessageJSONBody>} options The options to provide
160
160
  * @returns {Promise<Message>}
161
161
  * @example
162
162
  * // Send a basic message
@@ -683,3 +683,13 @@
683
683
  * @external WebhookType
684
684
  * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/enum/WebhookType}
685
685
  */
686
+
687
+ /**
688
+ * @external RESTPatchAPIChannelMessageJSONBody
689
+ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/RESTPatchAPIChannelMessageJSONBody}
690
+ */
691
+
692
+ /**
693
+ * @external RESTPostAPIChannelMessageJSONBody
694
+ * @see {@link https://discord-api-types.dev/api/discord-api-types-v10/interface/RESTPostAPIChannelMessageJSONBody}
695
+ */