discord.js 14.21.0 → 14.22.0

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": "14.21.0",
4
+ "version": "14.22.0",
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",
@@ -58,13 +58,13 @@
58
58
  "@discordjs/formatters": "^0.6.1",
59
59
  "@discordjs/ws": "^1.2.3",
60
60
  "@sapphire/snowflake": "3.5.3",
61
- "discord-api-types": "^0.38.1",
61
+ "discord-api-types": "^0.38.16",
62
62
  "fast-deep-equal": "3.1.3",
63
63
  "lodash.snakecase": "4.1.1",
64
64
  "magic-bytes.js": "^1.10.0",
65
65
  "tslib": "^2.6.3",
66
66
  "undici": "6.21.3",
67
- "@discordjs/rest": "^2.5.1",
67
+ "@discordjs/rest": "^2.6.0",
68
68
  "@discordjs/util": "^1.1.1"
69
69
  },
70
70
  "devDependencies": {
@@ -522,7 +522,7 @@ class Client extends BaseClient {
522
522
  }
523
523
 
524
524
  /**
525
- * Calls {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
525
+ * Calls {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/eval} on a script
526
526
  * with the client as `this`.
527
527
  * @param {string} script Script to eval
528
528
  * @returns {*}
@@ -604,7 +604,7 @@ module.exports = Client;
604
604
  */
605
605
 
606
606
  /**
607
- * A {@link https://developer.twitter.com/en/docs/twitter-ids Twitter snowflake},
607
+ * A {@link https://docs.x.com/resources/fundamentals/x-ids Twitter snowflake},
608
608
  * except the epoch is 2015-01-01T00:00:00.000Z.
609
609
  *
610
610
  * If we have a snowflake '266241948824764416' we can represent it as binary:
@@ -638,6 +638,11 @@ module.exports = Client;
638
638
  * @see {@link https://discord.js.org/docs/packages/rest/stable/ImageURLOptions:Interface}
639
639
  */
640
640
 
641
+ /**
642
+ * @external EmojiURLOptions
643
+ * @see {@link https://discord.js.org/docs/packages/rest/stable/EmojiURLOptions:TypeAlias}
644
+ */
645
+
641
646
  /**
642
647
  * @external BaseImageURLOptions
643
648
  * @see {@link https://discord.js.org/docs/packages/rest/stable/BaseImageURLOptions:Interface}
@@ -19,6 +19,7 @@ const Status = require('../../util/Status');
19
19
  const WebSocketShardEvents = require('../../util/WebSocketShardEvents');
20
20
 
21
21
  let zlib;
22
+ let deprecationEmitted = false;
22
23
 
23
24
  try {
24
25
  zlib = require('zlib-sync');
@@ -379,6 +380,22 @@ class WebSocketManager extends EventEmitter {
379
380
  /**
380
381
  * Emitted when the client becomes ready to start working.
381
382
  * @event Client#ready
383
+ * @deprecated Use {@link Client#event:clientReady} instead.
384
+ * @param {Client} client The client
385
+ */
386
+ if (this.client.emit('ready', this.client) && !deprecationEmitted) {
387
+ deprecationEmitted = true;
388
+
389
+ process.emitWarning(
390
+ // eslint-disable-next-line max-len
391
+ 'The ready event has been renamed to clientReady to distinguish it from the gateway READY event and will only emit under that name in v15. Please use clientReady instead.',
392
+ 'DeprecationWarning',
393
+ );
394
+ }
395
+
396
+ /**
397
+ * Emitted when the client becomes ready to start working.
398
+ * @event Client#clientReady
382
399
  * @param {Client} client The client
383
400
  */
384
401
  this.client.emit(Events.ClientReady, this.client);
package/src/index.js CHANGED
@@ -126,6 +126,7 @@ exports.CommandInteractionOptionResolver = require('./structures/CommandInteract
126
126
  exports.Component = require('./structures/Component');
127
127
  exports.ContainerComponent = require('./structures/ContainerComponent');
128
128
  exports.ContextMenuCommandInteraction = require('./structures/ContextMenuCommandInteraction');
129
+ exports.DirectoryChannel = require('./structures/DirectoryChannel');
129
130
  exports.DMChannel = require('./structures/DMChannel');
130
131
  exports.Embed = require('./structures/Embed');
131
132
  exports.EmbedBuilder = require('./structures/EmbedBuilder');
@@ -230,13 +230,13 @@ class GuildChannelManager extends CachedManager {
230
230
  async createWebhook({ channel, name, avatar, reason }) {
231
231
  const id = this.resolveId(channel);
232
232
  if (!id) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'channel', 'GuildChannelResolvable');
233
- if (typeof avatar === 'string' && !avatar.startsWith('data:')) {
234
- avatar = await resolveImage(avatar);
235
- }
233
+
234
+ const resolvedImage = await resolveImage(avatar);
235
+
236
236
  const data = await this.client.rest.post(Routes.channelWebhooks(id), {
237
237
  body: {
238
238
  name,
239
- avatar,
239
+ avatar: resolvedImage,
240
240
  },
241
241
  reason,
242
242
  });
@@ -65,7 +65,7 @@ class GuildMemberRoleManager extends DataManager {
65
65
  * @readonly
66
66
  */
67
67
  get color() {
68
- const coloredRoles = this.cache.filter(role => role.color);
68
+ const coloredRoles = this.cache.filter(role => role.colors.primaryColor);
69
69
  if (!coloredRoles.size) return null;
70
70
  return coloredRoles.reduce((prev, role) => (role.comparePositionTo(prev) > 0 ? role : prev));
71
71
  }
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const process = require('node:process');
3
4
  const { Collection } = require('@discordjs/collection');
4
5
  const { makeURLSearchParams } = require('@discordjs/rest');
5
6
  const { Routes } = require('discord-api-types/v10');
@@ -10,6 +11,8 @@ const MessagePayload = require('../structures/MessagePayload');
10
11
  const { MakeCacheOverrideSymbol } = require('../util/Symbols');
11
12
  const { resolvePartialEmoji } = require('../util/Util');
12
13
 
14
+ let deprecationEmittedForFetchPinned = false;
15
+
13
16
  /**
14
17
  * Manages API methods for Messages and holds their cache.
15
18
  * @extends {CachedManager}
@@ -116,19 +119,83 @@ class MessageManager extends CachedManager {
116
119
  return data.reduce((_data, message) => _data.set(message.id, this._add(message, options.cache)), new Collection());
117
120
  }
118
121
 
122
+ /**
123
+ * Options used to fetch pinned messages.
124
+ *
125
+ * @typedef {Object} FetchPinnedMessagesOptions
126
+ * @property {DateResolvable} [before] Consider only pinned messages before this time
127
+ * @property {number} [limit] The maximum number of pinned messages to return
128
+ * @property {boolean} [cache] Whether to cache the pinned messages
129
+ */
130
+
131
+ /**
132
+ * Data returned from fetching pinned messages.
133
+ *
134
+ * @typedef {Object} FetchPinnedMessagesResponse
135
+ * @property {MessagePin[]} items The pinned messages
136
+ * @property {boolean} hasMore Whether there are additional pinned messages that require a subsequent call
137
+ */
138
+
139
+ /**
140
+ * Pinned message data returned from fetching pinned messages.
141
+ *
142
+ * @typedef {Object} MessagePin
143
+ * @property {Date} pinnedAt The time the message was pinned at
144
+ * @property {number} pinnedTimestamp The timestamp the message was pinned at
145
+ * @property {Message} message The pinned message
146
+ */
147
+
119
148
  /**
120
149
  * Fetches the pinned messages of this channel and returns a collection of them.
121
150
  * <info>The returned Collection does not contain any reaction data of the messages.
122
151
  * Those need to be fetched separately.</info>
123
- * @param {boolean} [cache=true] Whether to cache the message(s)
124
- * @returns {Promise<Collection<Snowflake, Message>>}
152
+ *
153
+ * @param {FetchPinnedMessagesOptions} [options={}] Options for fetching pinned messages
154
+ * @returns {Promise<FetchPinnedMessagesResponse>}
125
155
  * @example
126
156
  * // Get pinned messages
127
- * channel.messages.fetchPinned()
128
- * .then(messages => console.log(`Received ${messages.size} messages`))
157
+ * channel.messages.fetchPins()
158
+ * .then(messages => console.log(`Received ${messages.items.length} messages`))
129
159
  * .catch(console.error);
130
160
  */
161
+ async fetchPins(options = {}) {
162
+ const data = await this.client.rest.get(Routes.channelMessagesPins(this.channel.id), {
163
+ query: makeURLSearchParams({
164
+ ...options,
165
+ before: options.before && new Date(options.before).toISOString(),
166
+ }),
167
+ });
168
+
169
+ return {
170
+ items: data.items.map(item => ({
171
+ pinnedTimestamp: Date.parse(item.pinned_at),
172
+ get pinnedAt() {
173
+ return new Date(this.pinnedTimestamp);
174
+ },
175
+ message: this._add(item.message, options.cache),
176
+ })),
177
+ hasMore: data.has_more,
178
+ };
179
+ }
180
+
181
+ /**
182
+ * Fetches the pinned messages of this channel and returns a collection of them.
183
+ * <info>The returned Collection does not contain any reaction data of the messages.
184
+ * Those need to be fetched separately.</info>
185
+ * @param {boolean} [cache=true] Whether to cache the message(s)
186
+ * @deprecated Use {@link MessageManager#fetchPins} instead.
187
+ * @returns {Promise<Collection<Snowflake, Message>>}
188
+ */
131
189
  async fetchPinned(cache = true) {
190
+ if (!deprecationEmittedForFetchPinned) {
191
+ process.emitWarning(
192
+ 'The MessageManager#fetchPinned() method is deprecated. Use MessageManager#fetchPins() instead.',
193
+ 'DeprecationWarning',
194
+ );
195
+
196
+ deprecationEmittedForFetchPinned = true;
197
+ }
198
+
132
199
  const data = await this.client.rest.get(Routes.channelPins(this.channel.id));
133
200
  const messages = new Collection();
134
201
  for (const message of data) messages.set(message.id, this._add(message, cache));
@@ -219,7 +286,7 @@ class MessageManager extends CachedManager {
219
286
  message = this.resolveId(message);
220
287
  if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
221
288
 
222
- await this.client.rest.put(Routes.channelPin(this.channel.id, message), { reason });
289
+ await this.client.rest.put(Routes.channelMessagesPin(this.channel.id, message), { reason });
223
290
  }
224
291
 
225
292
  /**
@@ -232,7 +299,7 @@ class MessageManager extends CachedManager {
232
299
  message = this.resolveId(message);
233
300
  if (!message) throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'message', 'MessageResolvable');
234
301
 
235
- await this.client.rest.delete(Routes.channelPin(this.channel.id, message), { reason });
302
+ await this.client.rest.delete(Routes.channelMessagesPin(this.channel.id, message), { reason });
236
303
  }
237
304
 
238
305
  /**
@@ -12,6 +12,8 @@ const PermissionsBitField = require('../util/PermissionsBitField');
12
12
  const { setPosition, resolveColor } = require('../util/Util');
13
13
 
14
14
  let cacheWarningEmitted = false;
15
+ let deprecationEmittedForCreate = false;
16
+ let deprecationEmittedForEdit = false;
15
17
 
16
18
  /**
17
19
  * Manages API methods for roles and stores their cache.
@@ -58,7 +60,7 @@ class RoleManager extends CachedManager {
58
60
  * @example
59
61
  * // Fetch a single role
60
62
  * message.guild.roles.fetch('222078108977594368')
61
- * .then(role => console.log(`The role color is: ${role.color}`))
63
+ * .then(role => console.log(`The role color is: ${role.colors.primaryColor}`))
62
64
  * .catch(console.error);
63
65
  */
64
66
  async fetch(id, { cache = true, force = false } = {}) {
@@ -112,11 +114,24 @@ class RoleManager extends CachedManager {
112
114
  * @returns {?Snowflake}
113
115
  */
114
116
 
117
+ /**
118
+ * @typedef {Object} RoleColorsResolvable
119
+ * @property {ColorResolvable} primaryColor The primary color of the role
120
+ * @property {ColorResolvable} [secondaryColor] The secondary color of the role.
121
+ * This will make the role a gradient between the other provided colors
122
+ * @property {ColorResolvable} [tertiaryColor] The tertiary color of the role.
123
+ * When sending `tertiaryColor` the API enforces the role color to be a holographic style
124
+ * with values of `primaryColor = 11127295`, `secondaryColor = 16759788`, and `tertiaryColor = 16761760`.
125
+ * These values are available as a constant: `Constants.HolographicStyle`
126
+ */
127
+
115
128
  /**
116
129
  * Options used to create a new role.
117
130
  * @typedef {Object} RoleCreateOptions
118
131
  * @property {string} [name] The name of the new role
119
132
  * @property {ColorResolvable} [color] The data to create the role with
133
+ * <warn>This property is deprecated. Use `colors` instead.</warn>
134
+ * @property {RoleColorsResolvable} [colors] The colors to create the role with
120
135
  * @property {boolean} [hoist] Whether or not the new role should be hoisted
121
136
  * @property {PermissionResolvable} [permissions] The permissions for the new role
122
137
  * @property {number} [position] The position of the new role
@@ -142,15 +157,30 @@ class RoleManager extends CachedManager {
142
157
  * // Create a new role with data and a reason
143
158
  * guild.roles.create({
144
159
  * name: 'Super Cool Blue People',
145
- * color: Colors.Blue,
146
160
  * reason: 'we needed a role for Super Cool People',
161
+ * colors: {
162
+ * primaryColor: Colors.Blue,
163
+ * },
164
+ * })
165
+ * .then(console.log)
166
+ * .catch(console.error);
167
+ * @example
168
+ * // Create a role with holographic colors
169
+ * guild.roles.create({
170
+ * name: 'Holographic Role',
171
+ * reason: 'Creating a role with holographic effect',
172
+ * colors: {
173
+ * primaryColor: Constants.HolographicStyle.Primary,
174
+ * secondaryColor: Constants.HolographicStyle.Secondary,
175
+ * tertiaryColor: Constants.HolographicStyle.Tertiary,
176
+ * },
147
177
  * })
148
178
  * .then(console.log)
149
179
  * .catch(console.error);
150
180
  */
151
181
  async create(options = {}) {
152
- let { name, color, hoist, permissions, position, mentionable, reason, icon, unicodeEmoji } = options;
153
- color &&= resolveColor(color);
182
+ let { permissions, icon } = options;
183
+ const { name, color, hoist, position, mentionable, reason, unicodeEmoji } = options;
154
184
  if (permissions !== undefined) permissions = new PermissionsBitField(permissions);
155
185
  if (icon) {
156
186
  const guildEmojiURL = this.guild.emojis.resolve(icon)?.imageURL();
@@ -158,10 +188,30 @@ class RoleManager extends CachedManager {
158
188
  if (typeof icon !== 'string') icon = undefined;
159
189
  }
160
190
 
191
+ let colors = options.colors && {
192
+ primary_color: resolveColor(options.colors.primaryColor),
193
+ secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),
194
+ tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),
195
+ };
196
+
197
+ if (color !== undefined) {
198
+ if (!deprecationEmittedForCreate) {
199
+ process.emitWarning(`Passing "color" to RoleManager#create() is deprecated. Use "colors" instead.`);
200
+ }
201
+
202
+ deprecationEmittedForCreate = true;
203
+
204
+ colors = {
205
+ primary_color: resolveColor(color),
206
+ secondary_color: null,
207
+ tertiary_color: null,
208
+ };
209
+ }
210
+
161
211
  const data = await this.client.rest.post(Routes.guildRoles(this.guild.id), {
162
212
  body: {
163
213
  name,
164
- color,
214
+ colors,
165
215
  hoist,
166
216
  permissions,
167
217
  mentionable,
@@ -210,9 +260,29 @@ class RoleManager extends CachedManager {
210
260
  if (typeof icon !== 'string') icon = undefined;
211
261
  }
212
262
 
263
+ let colors = options.colors && {
264
+ primary_color: resolveColor(options.colors.primaryColor),
265
+ secondary_color: options.colors.secondaryColor && resolveColor(options.colors.secondaryColor),
266
+ tertiary_color: options.colors.tertiaryColor && resolveColor(options.colors.tertiaryColor),
267
+ };
268
+
269
+ if (options.color !== undefined) {
270
+ if (!deprecationEmittedForEdit) {
271
+ process.emitWarning(`Passing "color" to RoleManager#edit() is deprecated. Use "colors" instead.`);
272
+ }
273
+
274
+ deprecationEmittedForEdit = true;
275
+
276
+ colors = {
277
+ primary_color: resolveColor(options.color),
278
+ secondary_color: null,
279
+ tertiary_color: null,
280
+ };
281
+ }
282
+
213
283
  const body = {
214
284
  name: options.name,
215
- color: options.color === undefined ? undefined : resolveColor(options.color),
285
+ colors,
216
286
  hoist: options.hoist,
217
287
  permissions: options.permissions === undefined ? undefined : new PermissionsBitField(options.permissions),
218
288
  mentionable: options.mentionable,
@@ -312,7 +312,7 @@ class ApplicationCommand extends Base {
312
312
  * @returns {Promise<ApplicationCommand>}
313
313
  * @example
314
314
  * // Edit the name localizations of this command
315
- * command.setLocalizedNames({
315
+ * command.setNameLocalizations({
316
316
  * 'en-GB': 'test',
317
317
  * 'pt-BR': 'teste',
318
318
  * })
@@ -16,37 +16,42 @@ class ApplicationEmoji extends Emoji {
16
16
  */
17
17
  this.application = application;
18
18
 
19
- /**
20
- * The user who created this emoji
21
- * @type {?User}
22
- */
23
- this.author = null;
24
-
25
- this.managed = null;
26
- this.requiresColons = null;
27
-
28
19
  this._patch(data);
29
20
  }
30
21
 
31
22
  _patch(data) {
32
23
  if ('name' in data) this.name = data.name;
33
- if (data.user) this.author = this.client.users._add(data.user);
24
+ if (data.user) {
25
+ /**
26
+ * The user who created this emoji
27
+ * @type {User}
28
+ */
29
+ this.author = this.client.users._add(data.user);
30
+ }
34
31
 
35
32
  if ('managed' in data) {
36
33
  /**
37
- * Whether this emoji is managed by an external service
38
- * @type {?boolean}
34
+ * Whether this emoji is managed by an external service. Always `false` for application emojis
35
+ * @type {false}
39
36
  */
40
37
  this.managed = data.managed;
41
38
  }
42
39
 
43
40
  if ('require_colons' in data) {
44
41
  /**
45
- * Whether or not this emoji requires colons surrounding it
46
- * @type {?boolean}
42
+ * Whether this emoji requires colons surrounding it. Always `true` for application emojis
43
+ * @type {true}
47
44
  */
48
45
  this.requiresColons = data.require_colons;
49
46
  }
47
+
48
+ if ('available' in data) {
49
+ /**
50
+ * Whether this emoji is available. Always `true` for application emojis
51
+ * @type {true}
52
+ */
53
+ this.available = data.available;
54
+ }
50
55
  }
51
56
 
52
57
  /**
@@ -107,7 +112,8 @@ class ApplicationEmoji extends Emoji {
107
112
  other.id === this.id &&
108
113
  other.name === this.name &&
109
114
  other.managed === this.managed &&
110
- other.requiresColons === this.requiresColons
115
+ other.requiresColons === this.requiresColons &&
116
+ other.available === this.available
111
117
  );
112
118
  }
113
119
 
@@ -115,4 +121,49 @@ class ApplicationEmoji extends Emoji {
115
121
  }
116
122
  }
117
123
 
124
+ /**
125
+ * The emoji's name
126
+ * @name name
127
+ * @memberof ApplicationEmoji
128
+ * @instance
129
+ * @type {string}
130
+ * @readonly
131
+ */
132
+
133
+ /**
134
+ * Whether the emoji is animated
135
+ * @name animated
136
+ * @memberof ApplicationEmoji
137
+ * @instance
138
+ * @type {boolean}
139
+ * @readonly
140
+ */
141
+
142
+ /**
143
+ * Returns a URL for the emoji.
144
+ * @method imageURL
145
+ * @memberof ApplicationEmoji
146
+ * @instance
147
+ * @param {EmojiURLOptions} [options] Options for the image URL
148
+ * @returns {string}
149
+ */
150
+
151
+ /**
152
+ * The time the emoji was created at
153
+ * @name createdAt
154
+ * @memberof ApplicationEmoji
155
+ * @instance
156
+ * @type {Date}
157
+ * @readonly
158
+ */
159
+
160
+ /**
161
+ * The timestamp the emoji was created at
162
+ * @name createdTimestamp
163
+ * @memberof ApplicationEmoji
164
+ * @instance
165
+ * @type {number}
166
+ * @readonly
167
+ */
168
+
118
169
  module.exports = ApplicationEmoji;
@@ -58,7 +58,7 @@ class BaseGuildEmoji extends Emoji {
58
58
  * @method imageURL
59
59
  * @memberof BaseGuildEmoji
60
60
  * @instance
61
- * @param {BaseImageURLOptions} [options] Options for the image URL
61
+ * @param {EmojiURLOptions} [options] Options for the emoji URL
62
62
  * @returns {string}
63
63
  */
64
64
 
@@ -72,4 +72,40 @@ class BaseGuildEmoji extends Emoji {
72
72
  * @deprecated Use {@link BaseGuildEmoji#imageURL} instead.
73
73
  */
74
74
 
75
+ /**
76
+ * The emoji's name
77
+ * @name name
78
+ * @memberof BaseGuildEmoji
79
+ * @instance
80
+ * @type {string}
81
+ * @readonly
82
+ */
83
+
84
+ /**
85
+ * Whether or not the emoji is animated
86
+ * @name animated
87
+ * @memberof BaseGuildEmoji
88
+ * @instance
89
+ * @type {boolean}
90
+ * @readonly
91
+ */
92
+
93
+ /**
94
+ * The time the emoji was created at.
95
+ * @name createdAt
96
+ * @memberof BaseGuildEmoji
97
+ * @instance
98
+ * @type {Date}
99
+ * @readonly
100
+ */
101
+
102
+ /**
103
+ * The timestamp the emoji was created at.
104
+ * @name createdTimestamp
105
+ * @memberof BaseGuildEmoji
106
+ * @instance
107
+ * @type {number}
108
+ * @readonly
109
+ */
110
+
75
111
  module.exports = BaseGuildEmoji;
@@ -45,7 +45,7 @@ class Emoji extends Base {
45
45
 
46
46
  /**
47
47
  * Returns a URL for the emoji or `null` if this is not a custom emoji.
48
- * @param {BaseImageURLOptions} [options] Options for the image URL
48
+ * @param {EmojiURLOptions} [options] Options for the emoji URL
49
49
  * @returns {?string}
50
50
  */
51
51
  imageURL(options) {
@@ -270,7 +270,7 @@ class GuildMember extends Base {
270
270
  * @readonly
271
271
  */
272
272
  get displayColor() {
273
- return this.roles.color?.color ?? 0;
273
+ return this.roles.color?.colors.primaryColor ?? 0;
274
274
  }
275
275
 
276
276
  /**
@@ -812,6 +812,7 @@ class Message extends Base {
812
812
  return Boolean(
813
813
  channel?.type === ChannelType.GuildAnnouncement &&
814
814
  !this.flags.has(MessageFlags.Crossposted) &&
815
+ this.reference?.type !== MessageReferenceType.Forward &&
815
816
  this.type === MessageType.Default &&
816
817
  !this.poll &&
817
818
  channel.viewable &&