discord.js 15.0.0-dev.1739405525-4b63bb804 → 15.0.0-dev.1739664801-e3e3c212b

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-dev.1739405525-4b63bb804",
4
+ "version": "15.0.0-dev.1739664801-e3e3c212b",
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",
@@ -62,8 +62,8 @@
62
62
  "undici": "6.21.1",
63
63
  "@discordjs/collection": "^2.1.1",
64
64
  "@discordjs/formatters": "^0.5.0",
65
- "@discordjs/rest": "^2.4.0",
66
65
  "@discordjs/util": "^1.1.1",
66
+ "@discordjs/rest": "^2.4.0",
67
67
  "@discordjs/ws": "^2.0.0"
68
68
  },
69
69
  "devDependencies": {
@@ -81,9 +81,9 @@
81
81
  "tslint": "6.1.3",
82
82
  "turbo": "^2.3.3",
83
83
  "typescript": "~5.5.4",
84
- "@discordjs/api-extractor": "^7.38.1",
85
84
  "@discordjs/docgen": "^0.12.1",
86
- "@discordjs/scripts": "^0.1.0"
85
+ "@discordjs/scripts": "^0.1.0",
86
+ "@discordjs/api-extractor": "^7.38.1"
87
87
  },
88
88
  "engines": {
89
89
  "node": ">=22.12.0"
@@ -11,7 +11,6 @@ const { ActionsManager } = require('./actions/ActionsManager.js');
11
11
  const { ClientVoiceManager } = require('./voice/ClientVoiceManager.js');
12
12
  const { PacketHandlers } = require('./websocket/handlers/index.js');
13
13
  const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
14
- const { BaseGuildEmojiManager } = require('../managers/BaseGuildEmojiManager.js');
15
14
  const { ChannelManager } = require('../managers/ChannelManager.js');
16
15
  const { GuildManager } = require('../managers/GuildManager.js');
17
16
  const { UserManager } = require('../managers/UserManager.js');
@@ -217,19 +216,6 @@ class Client extends BaseClient {
217
216
  this._attachEvents();
218
217
  }
219
218
 
220
- /**
221
- * A manager of all the custom emojis that the client has access to
222
- * @type {BaseGuildEmojiManager}
223
- * @readonly
224
- */
225
- get emojis() {
226
- const emojis = new BaseGuildEmojiManager(this);
227
- for (const guild of this.guilds.cache.values()) {
228
- if (guild.available) for (const emoji of guild.emojis.cache.values()) emojis.cache.set(emoji.id, emoji);
229
- }
230
- return emojis;
231
- }
232
-
233
219
  /**
234
220
  * Time at which the client was last regarded as being in the {@link Status.Ready} state
235
221
  * (each time the client disconnects and successfully reconnects, this will be overwritten)
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { Poll } = require('../../structures/Poll.js');
4
+ const { PollAnswer } = require('../../structures/PollAnswer.js');
3
5
  const { Partials } = require('../../util/Partials.js');
4
6
 
5
7
  /*
@@ -63,6 +65,23 @@ class Action {
63
65
  );
64
66
  }
65
67
 
68
+ getPoll(data, message, channel) {
69
+ const includePollPartial = this.client.options.partials.includes(Partials.Poll);
70
+ const includePollAnswerPartial = this.client.options.partials.includes(Partials.PollAnswer);
71
+ if (message.partial && (!includePollPartial || !includePollAnswerPartial)) return null;
72
+
73
+ if (!message.poll && includePollPartial) {
74
+ message.poll = new Poll(this.client, data, message, channel);
75
+ }
76
+
77
+ if (message.poll && !message.poll.answers.has(data.answer_id) && includePollAnswerPartial) {
78
+ const pollAnswer = new PollAnswer(this.client, data, message.poll);
79
+ message.poll.answers.set(data.answer_id, pollAnswer);
80
+ }
81
+
82
+ return message.poll;
83
+ }
84
+
66
85
  getReaction(data, message, user) {
67
86
  const id = data.emoji.id ?? decodeURIComponent(data.emoji.name);
68
87
  return this.getPayload(
@@ -11,11 +11,18 @@ class MessagePollVoteAddAction extends Action {
11
11
  const message = this.getMessage(data, channel);
12
12
  if (!message) return false;
13
13
 
14
- const { poll } = message;
14
+ const poll = this.getPoll(data, message, channel);
15
+ if (!poll) return false;
15
16
 
16
- const answer = poll?.answers.get(data.answer_id);
17
+ const answer = poll.answers.get(data.answer_id);
17
18
  if (!answer) return false;
18
19
 
20
+ const user = this.getUser(data);
21
+
22
+ if (user) {
23
+ answer.voters._add(user);
24
+ }
25
+
19
26
  answer.voteCount++;
20
27
 
21
28
  /**
@@ -11,12 +11,17 @@ class MessagePollVoteRemoveAction extends Action {
11
11
  const message = this.getMessage(data, channel);
12
12
  if (!message) return false;
13
13
 
14
- const { poll } = message;
14
+ const poll = this.getPoll(data, message, channel);
15
+ if (!poll) return false;
15
16
 
16
- const answer = poll?.answers.get(data.answer_id);
17
+ const answer = poll.answers.get(data.answer_id);
17
18
  if (!answer) return false;
18
19
 
19
- answer.voteCount--;
20
+ answer.voters.cache.delete(data.user_id);
21
+
22
+ if (answer.voteCount > 0) {
23
+ answer.voteCount--;
24
+ }
20
25
 
21
26
  /**
22
27
  * Emitted whenever a user removes their vote in a poll.
package/src/index.js CHANGED
@@ -58,7 +58,6 @@ exports.ApplicationCommandPermissionsManager =
58
58
  require('./managers/ApplicationCommandPermissionsManager.js').ApplicationCommandPermissionsManager;
59
59
  exports.ApplicationEmojiManager = require('./managers/ApplicationEmojiManager.js').ApplicationEmojiManager;
60
60
  exports.AutoModerationRuleManager = require('./managers/AutoModerationRuleManager.js').AutoModerationRuleManager;
61
- exports.BaseGuildEmojiManager = require('./managers/BaseGuildEmojiManager.js').BaseGuildEmojiManager;
62
61
  exports.CachedManager = require('./managers/CachedManager.js').CachedManager;
63
62
  exports.ChannelManager = require('./managers/ChannelManager.js').ChannelManager;
64
63
  exports.ClientVoiceManager = require('./client/voice/ClientVoiceManager.js').ClientVoiceManager;
@@ -82,6 +81,7 @@ exports.GuildStickerManager = require('./managers/GuildStickerManager.js').Guild
82
81
  exports.GuildTextThreadManager = require('./managers/GuildTextThreadManager.js').GuildTextThreadManager;
83
82
  exports.MessageManager = require('./managers/MessageManager.js').MessageManager;
84
83
  exports.PermissionOverwriteManager = require('./managers/PermissionOverwriteManager.js').PermissionOverwriteManager;
84
+ exports.PollAnswerVoterManager = require('./managers/PollAnswerVoterManager.js').PollAnswerVoterManager;
85
85
  exports.PresenceManager = require('./managers/PresenceManager.js').PresenceManager;
86
86
  exports.ReactionManager = require('./managers/ReactionManager.js').ReactionManager;
87
87
  exports.ReactionUserManager = require('./managers/ReactionUserManager.js').ReactionUserManager;
@@ -1,18 +1,21 @@
1
1
  'use strict';
2
-
3
2
  const { Collection } = require('@discordjs/collection');
4
3
  const { Routes, PermissionFlagsBits } = require('discord-api-types/v10');
5
- const { BaseGuildEmojiManager } = require('./BaseGuildEmojiManager.js');
4
+ const { CachedManager } = require('./CachedManager.js');
6
5
  const { DiscordjsError, DiscordjsTypeError, ErrorCodes } = require('../errors/index.js');
6
+ const { ApplicationEmoji } = require('../structures/ApplicationEmoji.js');
7
+ const { GuildEmoji } = require('../structures/GuildEmoji.js');
8
+ const { ReactionEmoji } = require('../structures/ReactionEmoji.js');
7
9
  const { resolveImage } = require('../util/DataResolver.js');
10
+ const { parseEmoji } = require('../util/Util.js');
8
11
 
9
12
  /**
10
13
  * Manages API methods for GuildEmojis and stores their cache.
11
- * @extends {BaseGuildEmojiManager}
14
+ * @extends {CachedManager}
12
15
  */
13
- class GuildEmojiManager extends BaseGuildEmojiManager {
16
+ class GuildEmojiManager extends CachedManager {
14
17
  constructor(guild, iterable) {
15
- super(guild.client, iterable);
18
+ super(guild.client, GuildEmoji, iterable);
16
19
 
17
20
  /**
18
21
  * The guild this manager belongs to
@@ -25,6 +28,72 @@ class GuildEmojiManager extends BaseGuildEmojiManager {
25
28
  return super._add(data, cache, { extras: [this.guild] });
26
29
  }
27
30
 
31
+ /**
32
+ * The cache of GuildEmojis
33
+ * @type {Collection<Snowflake, GuildEmoji>}
34
+ * @name GuildEmojiManager#cache
35
+ */
36
+
37
+ /**
38
+ * Data that can be resolved into a GuildEmoji object. This can be:
39
+ * * A Snowflake
40
+ * * A GuildEmoji object
41
+ * * A ReactionEmoji object
42
+ * * An ApplicationEmoji object
43
+ * @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable
44
+ */
45
+
46
+ /**
47
+ * Resolves an EmojiResolvable to an Emoji object.
48
+ * @param {EmojiResolvable} emoji The Emoji resolvable to identify
49
+ * @returns {?GuildEmoji}
50
+ */
51
+ resolve(emoji) {
52
+ if (emoji instanceof ReactionEmoji) return super.cache.get(emoji.id) ?? null;
53
+ if (emoji instanceof ApplicationEmoji) return super.cache.get(emoji.id) ?? null;
54
+ return super.resolve(emoji);
55
+ }
56
+
57
+ /**
58
+ * Resolves an EmojiResolvable to an Emoji id string.
59
+ * @param {EmojiResolvable} emoji The Emoji resolvable to identify
60
+ * @returns {?Snowflake}
61
+ */
62
+ resolveId(emoji) {
63
+ if (emoji instanceof ReactionEmoji) return emoji.id;
64
+ if (emoji instanceof ApplicationEmoji) return emoji.id;
65
+ return super.resolveId(emoji);
66
+ }
67
+
68
+ /**
69
+ * Data that can be resolved to give an emoji identifier. This can be:
70
+ * * An EmojiResolvable
71
+ * * The `<a:name:id>`, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji
72
+ * * The Unicode representation of an emoji
73
+ * @typedef {string|EmojiResolvable} EmojiIdentifierResolvable
74
+ */
75
+
76
+ /**
77
+ * Resolves an EmojiResolvable to an emoji identifier.
78
+ * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve
79
+ * @returns {?string}
80
+ */
81
+ resolveIdentifier(emoji) {
82
+ const emojiResolvable = this.resolve(emoji);
83
+ if (emojiResolvable) return emojiResolvable.identifier;
84
+ if (emoji instanceof ReactionEmoji) return emoji.identifier;
85
+ if (emoji instanceof ApplicationEmoji) return emoji.identifier;
86
+ if (typeof emoji === 'string') {
87
+ const res = parseEmoji(emoji);
88
+ if (res?.name.length) {
89
+ emoji = `${res.animated ? 'a:' : ''}${res.name}${res.id ? `:${res.id}` : ''}`;
90
+ }
91
+ if (!emoji.includes('%')) return encodeURIComponent(emoji);
92
+ return emoji;
93
+ }
94
+ return null;
95
+ }
96
+
28
97
  /**
29
98
  * Options used for creating an emoji in a guild.
30
99
  * @typedef {Object} GuildEmojiCreateOptions
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const { Collection } = require('@discordjs/collection');
4
+ const { makeURLSearchParams } = require('@discordjs/rest');
5
+ const { Routes } = require('discord-api-types/v10');
6
+ const { CachedManager } = require('./CachedManager.js');
7
+ const { User } = require('../structures/User.js');
8
+
9
+ /**
10
+ * Manages API methods for users who voted on a poll and stores their cache.
11
+ * @extends {CachedManager}
12
+ */
13
+ class PollAnswerVoterManager extends CachedManager {
14
+ constructor(answer) {
15
+ super(answer.client, User);
16
+
17
+ /**
18
+ * The poll answer that this manager belongs to
19
+ * @type {PollAnswer}
20
+ */
21
+ this.answer = answer;
22
+ }
23
+
24
+ /**
25
+ * The cache of this manager
26
+ * @type {Collection<Snowflake, User>}
27
+ * @name PollAnswerVoterManager#cache
28
+ */
29
+
30
+ /**
31
+ * Fetches the users that voted on this poll answer. Resolves with a collection of users, mapped by their ids.
32
+ * @param {BaseFetchPollAnswerVotersOptions} [options={}] Options for fetching the users
33
+ * @returns {Promise<Collection<Snowflake, User>>}
34
+ */
35
+ async fetch({ after, limit } = {}) {
36
+ const poll = this.answer.poll;
37
+ const query = makeURLSearchParams({ limit, after });
38
+ const data = await this.client.rest.get(Routes.pollAnswerVoters(poll.channelId, poll.messageId, this.answer.id), {
39
+ query,
40
+ });
41
+
42
+ return data.users.reduce((coll, rawUser) => {
43
+ const user = this.client.users._add(rawUser);
44
+ this.cache.set(user.id, user);
45
+ return coll.set(user.id, user);
46
+ }, new Collection());
47
+ }
48
+ }
49
+
50
+ exports.PollAnswerVoterManager = PollAnswerVoterManager;
@@ -79,7 +79,7 @@ class GuildOnboardingPromptOption extends Base {
79
79
  */
80
80
  get emoji() {
81
81
  if (!this._emoji.id && !this._emoji.name) return null;
82
- return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);
82
+ return this.guild.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);
83
83
  }
84
84
  }
85
85
 
@@ -414,11 +414,15 @@ class Message extends Base {
414
414
  }
415
415
 
416
416
  if (data.poll) {
417
- /**
418
- * The poll that was sent with the message
419
- * @type {?Poll}
420
- */
421
- this.poll = new Poll(this.client, data.poll, this);
417
+ if (this.poll) {
418
+ this.poll._patch(data.poll);
419
+ } else {
420
+ /**
421
+ * The poll that was sent with the message
422
+ * @type {?Poll}
423
+ */
424
+ this.poll = new Poll(this.client, data.poll, this, this.channel);
425
+ }
422
426
  } else {
423
427
  this.poll ??= null;
424
428
  }
@@ -5,7 +5,7 @@ const { ApplicationEmoji } = require('./ApplicationEmoji.js');
5
5
  const { GuildEmoji } = require('./GuildEmoji.js');
6
6
  const { ReactionEmoji } = require('./ReactionEmoji.js');
7
7
  const { ReactionUserManager } = require('../managers/ReactionUserManager.js');
8
- const { flatten } = require('../util/Util.js');
8
+ const { flatten, resolveGuildEmoji } = require('../util/Util.js');
9
9
 
10
10
  /**
11
11
  * Represents a reaction to a message.
@@ -127,14 +127,9 @@ class MessageReaction {
127
127
  this._emoji = emoji;
128
128
  return emoji;
129
129
  }
130
- const emojis = this.message.client.emojis.cache;
131
- if (emojis.has(this._emoji.id)) {
132
- const emoji = emojis.get(this._emoji.id);
133
- this._emoji = emoji;
134
- return emoji;
135
- }
136
130
  }
137
- return this._emoji;
131
+ const emoji = resolveGuildEmoji(this.client, this._emoji.id);
132
+ return emoji ?? this._emoji;
138
133
  }
139
134
 
140
135
  /**
@@ -10,58 +10,38 @@ const { DiscordjsError, ErrorCodes } = require('../errors/index.js');
10
10
  * @extends {Base}
11
11
  */
12
12
  class Poll extends Base {
13
- constructor(client, data, message) {
13
+ constructor(client, data, message, channel) {
14
14
  super(client);
15
15
 
16
16
  /**
17
- * The message that started this poll
18
- * @name Poll#message
19
- * @type {Message}
20
- * @readonly
17
+ * The id of the channel that this poll is in
18
+ * @type {Snowflake}
21
19
  */
22
-
23
- Object.defineProperty(this, 'message', { value: message });
20
+ this.channelId = data.channel_id ?? channel.id;
24
21
 
25
22
  /**
26
- * The media for a poll's question
27
- * @typedef {Object} PollQuestionMedia
28
- * @property {string} text The text of this question
29
- */
30
-
31
- /**
32
- * The media for this poll's question
33
- * @type {PollQuestionMedia}
23
+ * The channel that this poll is in
24
+ * @name Poll#channel
25
+ * @type {TextBasedChannel}
26
+ * @readonly
34
27
  */
35
- this.question = {
36
- text: data.question.text,
37
- };
38
28
 
39
- /**
40
- * The answers of this poll
41
- * @type {Collection<number, PollAnswer>}
42
- */
43
- this.answers = data.answers.reduce(
44
- (acc, answer) => acc.set(answer.answer_id, new PollAnswer(this.client, answer, this)),
45
- new Collection(),
46
- );
29
+ Object.defineProperty(this, 'channel', { value: channel });
47
30
 
48
31
  /**
49
- * The timestamp when this poll expires
50
- * @type {number}
32
+ * The id of the message that started this poll
33
+ * @type {Snowflake}
51
34
  */
52
- this.expiresTimestamp = Date.parse(data.expiry);
35
+ this.messageId = data.message_id ?? message.id;
53
36
 
54
37
  /**
55
- * Whether this poll allows multiple answers
56
- * @type {boolean}
38
+ * The message that started this poll
39
+ * @name Poll#message
40
+ * @type {Message}
41
+ * @readonly
57
42
  */
58
- this.allowMultiselect = data.allow_multiselect;
59
43
 
60
- /**
61
- * The layout type of this poll
62
- * @type {PollLayoutType}
63
- */
64
- this.layoutType = data.layout_type;
44
+ Object.defineProperty(this, 'message', { value: message });
65
45
 
66
46
  this._patch(data);
67
47
  }
@@ -81,15 +61,101 @@ class Poll extends Base {
81
61
  } else {
82
62
  this.resultsFinalized ??= false;
83
63
  }
64
+
65
+ if ('allow_multiselect' in data) {
66
+ /**
67
+ * Whether this poll allows multiple answers
68
+ * @type {boolean}
69
+ */
70
+ this.allowMultiselect = data.allow_multiselect;
71
+ } else {
72
+ this.allowMultiselect ??= null;
73
+ }
74
+
75
+ if ('layout_type' in data) {
76
+ /**
77
+ * The layout type of this poll
78
+ * @type {PollLayoutType}
79
+ */
80
+ this.layoutType = data.layout_type;
81
+ } else {
82
+ this.layoutType ??= null;
83
+ }
84
+
85
+ if ('expiry' in data) {
86
+ /**
87
+ * The timestamp when this poll expires
88
+ * @type {?number}
89
+ */
90
+ this.expiresTimestamp = data.expiry && Date.parse(data.expiry);
91
+ } else {
92
+ this.expiresTimestamp ??= null;
93
+ }
94
+
95
+ if (data.question) {
96
+ /**
97
+ * The media for a poll's question
98
+ * @typedef {Object} PollQuestionMedia
99
+ * @property {?string} text The text of this question
100
+ */
101
+
102
+ /**
103
+ * The media for this poll's question
104
+ * @type {PollQuestionMedia}
105
+ */
106
+ this.question = {
107
+ text: data.question.text,
108
+ };
109
+ } else {
110
+ this.question ??= {
111
+ text: null,
112
+ };
113
+ }
114
+
115
+ /**
116
+ * The answers of this poll
117
+ * @type {Collection<number, PollAnswer|PartialPollAnswer>}
118
+ */
119
+ this.answers ??= new Collection();
120
+
121
+ if (data.answers) {
122
+ for (const answer of data.answers) {
123
+ const existing = this.answers.get(answer.answer_id);
124
+ if (existing) {
125
+ existing._patch(answer);
126
+ } else {
127
+ this.answers.set(answer.answer_id, new PollAnswer(this.client, answer, this));
128
+ }
129
+ }
130
+ }
84
131
  }
85
132
 
86
133
  /**
87
134
  * The date when this poll expires
88
- * @type {Date}
135
+ * @type {?Date}
89
136
  * @readonly
90
137
  */
91
138
  get expiresAt() {
92
- return new Date(this.expiresTimestamp);
139
+ return this.expiresTimestamp && new Date(this.expiresTimestamp);
140
+ }
141
+
142
+ /**
143
+ * Whether this poll is a partial
144
+ * @type {boolean}
145
+ * @readonly
146
+ */
147
+ get partial() {
148
+ return this.allowMultiselect === null;
149
+ }
150
+
151
+ /**
152
+ * Fetches the message that started this poll, then updates the poll from the fetched message.
153
+ * @returns {Promise<Poll>}
154
+ */
155
+ async fetch() {
156
+ await this.channel.messages.fetch(this.messageId);
157
+
158
+ return this;
93
159
  }
94
160
 
95
161
  /**
@@ -101,7 +167,7 @@ class Poll extends Base {
101
167
  throw new DiscordjsError(ErrorCodes.PollAlreadyExpired);
102
168
  }
103
169
 
104
- return this.message.channel.messages.endPoll(this.message.id);
170
+ return this.channel.messages.endPoll(this.messageId);
105
171
  }
106
172
  }
107
173
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  const { Base } = require('./Base.js');
4
4
  const { Emoji } = require('./Emoji.js');
5
+ const { PollAnswerVoterManager } = require('../managers/PollAnswerVoterManager.js');
6
+ const { resolveGuildEmoji } = require('../util/Util.js');
5
7
 
6
8
  /**
7
9
  * Represents an answer to a {@link Poll}
@@ -14,7 +16,7 @@ class PollAnswer extends Base {
14
16
  /**
15
17
  * The {@link Poll} this answer is part of
16
18
  * @name PollAnswer#poll
17
- * @type {Poll}
19
+ * @type {Poll|PartialPoll}
18
20
  * @readonly
19
21
  */
20
22
  Object.defineProperty(this, 'poll', { value: poll });
@@ -26,10 +28,10 @@ class PollAnswer extends Base {
26
28
  this.id = data.answer_id;
27
29
 
28
30
  /**
29
- * The text of this answer
30
- * @type {?string}
31
+ * The manager of the voters for this answer
32
+ * @type {PollAnswerVoterManager}
31
33
  */
32
- this.text = data.poll_media.text ?? null;
34
+ this.voters = new PollAnswerVoterManager(this);
33
35
 
34
36
  /**
35
37
  * The raw emoji of this answer
@@ -37,7 +39,7 @@ class PollAnswer extends Base {
37
39
  * @type {?APIPartialEmoji}
38
40
  * @private
39
41
  */
40
- Object.defineProperty(this, '_emoji', { value: data.poll_media.emoji ?? null });
42
+ Object.defineProperty(this, '_emoji', { value: null });
41
43
 
42
44
  this._patch(data);
43
45
  }
@@ -51,7 +53,17 @@ class PollAnswer extends Base {
51
53
  */
52
54
  this.voteCount = data.count;
53
55
  } else {
54
- this.voteCount ??= 0;
56
+ this.voteCount ??= this.voters.cache.size;
57
+ }
58
+
59
+ /**
60
+ * The text of this answer
61
+ * @type {?string}
62
+ */
63
+ this.text ??= data.poll_media?.text ?? null;
64
+
65
+ if (data.poll_media?.emoji) {
66
+ Object.defineProperty(this, '_emoji', { value: data.poll_media.emoji });
55
67
  }
56
68
  }
57
69
 
@@ -61,7 +73,16 @@ class PollAnswer extends Base {
61
73
  */
62
74
  get emoji() {
63
75
  if (!this._emoji || (!this._emoji.id && !this._emoji.name)) return null;
64
- return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);
76
+ return resolveGuildEmoji(this.client, this._emoji.id) ?? new Emoji(this.client, this._emoji);
77
+ }
78
+
79
+ /**
80
+ * Whether this poll answer is a partial.
81
+ * @type {boolean}
82
+ * @readonly
83
+ */
84
+ get partial() {
85
+ return this.poll.partial || (this.text === null && this.emoji === null);
65
86
  }
66
87
 
67
88
  /**
@@ -75,14 +96,10 @@ class PollAnswer extends Base {
75
96
  * Fetches the users that voted for this answer.
76
97
  * @param {BaseFetchPollAnswerVotersOptions} [options={}] The options for fetching voters
77
98
  * @returns {Promise<Collection<Snowflake, User>>}
99
+ * @deprecated Use {@link PollAnswerVoterManager#fetch} instead
78
100
  */
79
101
  fetchVoters({ after, limit } = {}) {
80
- return this.poll.message.channel.messages.fetchPollAnswerVoters({
81
- messageId: this.poll.message.id,
82
- answerId: this.id,
83
- after,
84
- limit,
85
- });
102
+ return this.voters.fetch({ after, limit });
86
103
  }
87
104
  }
88
105
 
@@ -53,7 +53,7 @@ class WelcomeChannel extends Base {
53
53
  * @type {GuildEmoji|Emoji}
54
54
  */
55
55
  get emoji() {
56
- return this.client.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);
56
+ return this.guild.emojis.cache.get(this._emoji.id) ?? new Emoji(this.client, this._emoji);
57
57
  }
58
58
  }
59
59
 
@@ -26,6 +26,8 @@ const { createEnum } = require('./Enums.js');
26
26
  * @property {number} Reaction The partial to receive uncached reactions.
27
27
  * @property {number} GuildScheduledEvent The partial to receive uncached guild scheduled events.
28
28
  * @property {number} ThreadMember The partial to receive uncached thread members.
29
+ * @property {number} Poll The partial to receive uncached polls.
30
+ * @property {number} PollAnswer The partial to receive uncached poll answers.
29
31
  */
30
32
 
31
33
  // JSDoc for IntelliSense purposes
@@ -41,4 +43,6 @@ exports.Partials = createEnum([
41
43
  'Reaction',
42
44
  'GuildScheduledEvent',
43
45
  'ThreadMember',
46
+ 'Poll',
47
+ 'PollAnswer',
44
48
  ]);
package/src/util/Util.js CHANGED
@@ -122,6 +122,29 @@ function resolvePartialEmoji(emoji) {
122
122
  return { id, name, animated: Boolean(animated) };
123
123
  }
124
124
 
125
+ /**
126
+ * Resolves a {@link GuildEmoji} from an emoji id.
127
+ * @param {Client} client The client to use to resolve the emoji
128
+ * @param {Snowflake} emojiId The emoji id to resolve
129
+ * @returns {?GuildEmoji}
130
+ * @private
131
+ */
132
+ function resolveGuildEmoji(client, emojiId) {
133
+ for (const guild of client.guilds.cache.values()) {
134
+ if (!guild.available) {
135
+ continue;
136
+ }
137
+
138
+ const emoji = guild.emojis.cache.get(emojiId);
139
+
140
+ if (emoji) {
141
+ return emoji;
142
+ }
143
+ }
144
+
145
+ return null;
146
+ }
147
+
125
148
  /**
126
149
  * Options used to make an error object.
127
150
  * @typedef {Object} MakeErrorOptions
@@ -503,6 +526,7 @@ exports.flatten = flatten;
503
526
  exports.fetchRecommendedShardCount = fetchRecommendedShardCount;
504
527
  exports.parseEmoji = parseEmoji;
505
528
  exports.resolvePartialEmoji = resolvePartialEmoji;
529
+ exports.resolveGuildEmoji = resolveGuildEmoji;
506
530
  exports.makeError = makeError;
507
531
  exports.makePlainError = makePlainError;
508
532
  exports.getSortableGroupTypes = getSortableGroupTypes;
@@ -976,7 +976,6 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
976
976
 
977
977
  public application: If<Ready, ClientApplication>;
978
978
  public channels: ChannelManager;
979
- public get emojis(): BaseGuildEmojiManager;
980
979
  public guilds: GuildManager;
981
980
  public lastPingTimestamps: ReadonlyCollection<number, number>;
982
981
  public options: Omit<ClientOptions, 'intents'> & { intents: IntentsBitField };
@@ -2676,19 +2675,30 @@ export class Presence extends Base {
2676
2675
  }
2677
2676
 
2678
2677
  export interface PollQuestionMedia {
2679
- text: string;
2678
+ text: string | null;
2679
+ }
2680
+
2681
+ export class PollAnswerVoterManager extends CachedManager<Snowflake, User, UserResolvable> {
2682
+ private constructor(answer: PollAnswer);
2683
+ public answer: PollAnswer;
2684
+ public fetch(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;
2680
2685
  }
2681
2686
 
2682
2687
  export class Poll extends Base {
2683
- private constructor(client: Client<true>, data: APIPoll, message: Message);
2688
+ private constructor(client: Client<true>, data: APIPoll, message: Message, channel: TextBasedChannel);
2689
+ public readonly channel: TextBasedChannel;
2690
+ public channelId: Snowflake;
2684
2691
  public readonly message: Message;
2692
+ public messageId: Snowflake;
2685
2693
  public question: PollQuestionMedia;
2686
- public answers: Collection<number, PollAnswer>;
2687
- public expiresTimestamp: number;
2688
- public get expiresAt(): Date;
2694
+ public answers: Collection<number, PollAnswer | PartialPollAnswer>;
2695
+ public expiresTimestamp: number | null;
2696
+ public get expiresAt(): Date | null;
2689
2697
  public allowMultiselect: boolean;
2690
2698
  public layoutType: PollLayoutType;
2691
2699
  public resultsFinalized: boolean;
2700
+ public get partial(): false;
2701
+ public fetch(): Promise<this>;
2692
2702
  public end(): Promise<Message>;
2693
2703
  }
2694
2704
 
@@ -2700,11 +2710,14 @@ export interface BaseFetchPollAnswerVotersOptions {
2700
2710
  export class PollAnswer extends Base {
2701
2711
  private constructor(client: Client<true>, data: APIPollAnswer & { count?: number }, poll: Poll);
2702
2712
  private _emoji: APIPartialEmoji | null;
2703
- public readonly poll: Poll;
2713
+ public readonly poll: Poll | PartialPoll;
2704
2714
  public id: number;
2705
2715
  public text: string | null;
2706
2716
  public voteCount: number;
2717
+ public voters: PollAnswerVoterManager;
2707
2718
  public get emoji(): GuildEmoji | Emoji | null;
2719
+ public get partial(): false;
2720
+ /** @deprecated Use {@link PollAnswerVoterManager.fetch} instead */
2708
2721
  public fetchVoters(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;
2709
2722
  }
2710
2723
 
@@ -3456,6 +3469,7 @@ export function discordSort<Key, Value extends { rawPosition: number; id: Snowfl
3456
3469
  export function cleanCodeBlockContent(text: string): string;
3457
3470
  export function fetchRecommendedShardCount(token: string, options?: FetchRecommendedShardCountOptions): Promise<number>;
3458
3471
  export function flatten(obj: unknown, ...props: Record<string, boolean | string>[]): unknown;
3472
+
3459
3473
  /** @internal */
3460
3474
  export function makeError(obj: MakeErrorOptions): Error;
3461
3475
  /** @internal */
@@ -3474,6 +3488,8 @@ export function resolveColor(color: ColorResolvable): number;
3474
3488
  export function resolvePartialEmoji(emoji: Snowflake): PartialEmojiOnlyId;
3475
3489
  /** @internal */
3476
3490
  export function resolvePartialEmoji(emoji: Emoji | EmojiIdentifierResolvable): PartialEmoji | null;
3491
+ /** @internal */
3492
+ export function resolveGuildEmoji(client: Client, emojiId: Snowflake): GuildEmoji | null;
3477
3493
  export function verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string;
3478
3494
  /** @internal */
3479
3495
  export function setPosition<Item extends Channel | Role>(
@@ -3997,11 +4013,6 @@ export class AutoModerationRuleManager extends CachedManager<
3997
4013
  public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise<void>;
3998
4014
  }
3999
4015
 
4000
- export class BaseGuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> {
4001
- protected constructor(client: Client<true>, iterable?: Iterable<RawGuildEmojiData>);
4002
- public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;
4003
- }
4004
-
4005
4016
  export class CategoryChannelChildManager extends DataManager<Snowflake, CategoryChildChannel, GuildChannelResolvable> {
4006
4017
  private constructor(channel: CategoryChannel);
4007
4018
 
@@ -4142,7 +4153,7 @@ export class GuildChannelManager extends CachedManager<Snowflake, GuildBasedChan
4142
4153
  public delete(channel: GuildChannelResolvable, reason?: string): Promise<void>;
4143
4154
  }
4144
4155
 
4145
- export class GuildEmojiManager extends BaseGuildEmojiManager {
4156
+ export class GuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> {
4146
4157
  private constructor(guild: Guild, iterable?: Iterable<RawGuildEmojiData>);
4147
4158
  public guild: Guild;
4148
4159
  public create(options: GuildEmojiCreateOptions): Promise<GuildEmoji>;
@@ -4151,6 +4162,7 @@ export class GuildEmojiManager extends BaseGuildEmojiManager {
4151
4162
  public fetchAuthor(emoji: EmojiResolvable): Promise<User>;
4152
4163
  public delete(emoji: EmojiResolvable, reason?: string): Promise<void>;
4153
4164
  public edit(emoji: EmojiResolvable, options: GuildEmojiEditOptions): Promise<GuildEmoji>;
4165
+ public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;
4154
4166
  }
4155
4167
 
4156
4168
  export class GuildEmojiRoleManager extends DataManager<Snowflake, Role, RoleResolvable> {
@@ -4574,7 +4586,9 @@ export type AllowedPartial =
4574
4586
  | Message
4575
4587
  | MessageReaction
4576
4588
  | GuildScheduledEvent
4577
- | ThreadMember;
4589
+ | ThreadMember
4590
+ | Poll
4591
+ | PollAnswer;
4578
4592
 
4579
4593
  export type AllowedThreadTypeForAnnouncementChannel = ChannelType.AnnouncementThread;
4580
4594
 
@@ -4969,7 +4983,6 @@ export interface Caches {
4969
4983
  ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand];
4970
4984
  ApplicationEmojiManager: [manager: typeof ApplicationEmojiManager, holds: typeof ApplicationEmoji];
4971
4985
  AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule];
4972
- BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji];
4973
4986
  // TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel];
4974
4987
  DMMessageManager: [manager: typeof MessageManager, holds: typeof Message<false>];
4975
4988
  EntitlementManager: [manager: typeof EntitlementManager, holds: typeof Entitlement];
@@ -5126,8 +5139,8 @@ export interface ClientEventTypes {
5126
5139
  inviteDelete: [invite: Invite];
5127
5140
  messageCreate: [message: OmitPartialGroupDMChannel<Message>];
5128
5141
  messageDelete: [message: OmitPartialGroupDMChannel<Message | PartialMessage>];
5129
- messagePollVoteAdd: [pollAnswer: PollAnswer, userId: Snowflake];
5130
- messagePollVoteRemove: [pollAnswer: PollAnswer, userId: Snowflake];
5142
+ messagePollVoteAdd: [pollAnswer: PollAnswer | PartialPollAnswer, userId: Snowflake];
5143
+ messagePollVoteRemove: [pollAnswer: PollAnswer | PartialPollAnswer, userId: Snowflake];
5131
5144
  messageReactionRemoveAll: [
5132
5145
  message: OmitPartialGroupDMChannel<Message | PartialMessage>,
5133
5146
  reactions: ReadonlyCollection<string | Snowflake, MessageReaction>,
@@ -6539,6 +6552,23 @@ export interface PartialMessage
6539
6552
 
6540
6553
  export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {}
6541
6554
 
6555
+ export interface PartialPoll
6556
+ extends Partialize<
6557
+ Poll,
6558
+ 'allowMultiselect' | 'layoutType' | 'expiresTimestamp',
6559
+ null,
6560
+ 'question' | 'message' | 'answers'
6561
+ > {
6562
+ question: { text: null };
6563
+ message: PartialMessage;
6564
+ // eslint-disable-next-line no-restricted-syntax
6565
+ answers: Collection<number, PartialPollAnswer>;
6566
+ }
6567
+
6568
+ export interface PartialPollAnswer extends Partialize<PollAnswer, 'emoji' | 'text', null, 'poll'> {
6569
+ readonly poll: PartialPoll;
6570
+ }
6571
+
6542
6572
  export interface PartialGuildScheduledEvent
6543
6573
  extends Partialize<GuildScheduledEvent, 'userCount', 'status' | 'privacyLevel' | 'name' | 'entityType'> {}
6544
6574
 
@@ -6563,6 +6593,8 @@ export enum Partials {
6563
6593
  Reaction,
6564
6594
  GuildScheduledEvent,
6565
6595
  ThreadMember,
6596
+ Poll,
6597
+ PollAnswer,
6566
6598
  }
6567
6599
 
6568
6600
  export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {}
@@ -976,7 +976,6 @@ export class Client<Ready extends boolean = boolean> extends BaseClient<ClientEv
976
976
 
977
977
  public application: If<Ready, ClientApplication>;
978
978
  public channels: ChannelManager;
979
- public get emojis(): BaseGuildEmojiManager;
980
979
  public guilds: GuildManager;
981
980
  public lastPingTimestamps: ReadonlyCollection<number, number>;
982
981
  public options: Omit<ClientOptions, 'intents'> & { intents: IntentsBitField };
@@ -2676,19 +2675,30 @@ export class Presence extends Base {
2676
2675
  }
2677
2676
 
2678
2677
  export interface PollQuestionMedia {
2679
- text: string;
2678
+ text: string | null;
2679
+ }
2680
+
2681
+ export class PollAnswerVoterManager extends CachedManager<Snowflake, User, UserResolvable> {
2682
+ private constructor(answer: PollAnswer);
2683
+ public answer: PollAnswer;
2684
+ public fetch(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;
2680
2685
  }
2681
2686
 
2682
2687
  export class Poll extends Base {
2683
- private constructor(client: Client<true>, data: APIPoll, message: Message);
2688
+ private constructor(client: Client<true>, data: APIPoll, message: Message, channel: TextBasedChannel);
2689
+ public readonly channel: TextBasedChannel;
2690
+ public channelId: Snowflake;
2684
2691
  public readonly message: Message;
2692
+ public messageId: Snowflake;
2685
2693
  public question: PollQuestionMedia;
2686
- public answers: Collection<number, PollAnswer>;
2687
- public expiresTimestamp: number;
2688
- public get expiresAt(): Date;
2694
+ public answers: Collection<number, PollAnswer | PartialPollAnswer>;
2695
+ public expiresTimestamp: number | null;
2696
+ public get expiresAt(): Date | null;
2689
2697
  public allowMultiselect: boolean;
2690
2698
  public layoutType: PollLayoutType;
2691
2699
  public resultsFinalized: boolean;
2700
+ public get partial(): false;
2701
+ public fetch(): Promise<this>;
2692
2702
  public end(): Promise<Message>;
2693
2703
  }
2694
2704
 
@@ -2700,11 +2710,14 @@ export interface BaseFetchPollAnswerVotersOptions {
2700
2710
  export class PollAnswer extends Base {
2701
2711
  private constructor(client: Client<true>, data: APIPollAnswer & { count?: number }, poll: Poll);
2702
2712
  private _emoji: APIPartialEmoji | null;
2703
- public readonly poll: Poll;
2713
+ public readonly poll: Poll | PartialPoll;
2704
2714
  public id: number;
2705
2715
  public text: string | null;
2706
2716
  public voteCount: number;
2717
+ public voters: PollAnswerVoterManager;
2707
2718
  public get emoji(): GuildEmoji | Emoji | null;
2719
+ public get partial(): false;
2720
+ /** @deprecated Use {@link PollAnswerVoterManager.fetch} instead */
2708
2721
  public fetchVoters(options?: BaseFetchPollAnswerVotersOptions): Promise<Collection<Snowflake, User>>;
2709
2722
  }
2710
2723
 
@@ -3456,6 +3469,7 @@ export function discordSort<Key, Value extends { rawPosition: number; id: Snowfl
3456
3469
  export function cleanCodeBlockContent(text: string): string;
3457
3470
  export function fetchRecommendedShardCount(token: string, options?: FetchRecommendedShardCountOptions): Promise<number>;
3458
3471
  export function flatten(obj: unknown, ...props: Record<string, boolean | string>[]): unknown;
3472
+
3459
3473
  /** @internal */
3460
3474
  export function makeError(obj: MakeErrorOptions): Error;
3461
3475
  /** @internal */
@@ -3474,6 +3488,8 @@ export function resolveColor(color: ColorResolvable): number;
3474
3488
  export function resolvePartialEmoji(emoji: Snowflake): PartialEmojiOnlyId;
3475
3489
  /** @internal */
3476
3490
  export function resolvePartialEmoji(emoji: Emoji | EmojiIdentifierResolvable): PartialEmoji | null;
3491
+ /** @internal */
3492
+ export function resolveGuildEmoji(client: Client, emojiId: Snowflake): GuildEmoji | null;
3477
3493
  export function verifyString(data: string, error?: typeof Error, errorMessage?: string, allowEmpty?: boolean): string;
3478
3494
  /** @internal */
3479
3495
  export function setPosition<Item extends Channel | Role>(
@@ -3997,11 +4013,6 @@ export class AutoModerationRuleManager extends CachedManager<
3997
4013
  public delete(autoModerationRule: AutoModerationRuleResolvable, reason?: string): Promise<void>;
3998
4014
  }
3999
4015
 
4000
- export class BaseGuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> {
4001
- protected constructor(client: Client<true>, iterable?: Iterable<RawGuildEmojiData>);
4002
- public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;
4003
- }
4004
-
4005
4016
  export class CategoryChannelChildManager extends DataManager<Snowflake, CategoryChildChannel, GuildChannelResolvable> {
4006
4017
  private constructor(channel: CategoryChannel);
4007
4018
 
@@ -4142,7 +4153,7 @@ export class GuildChannelManager extends CachedManager<Snowflake, GuildBasedChan
4142
4153
  public delete(channel: GuildChannelResolvable, reason?: string): Promise<void>;
4143
4154
  }
4144
4155
 
4145
- export class GuildEmojiManager extends BaseGuildEmojiManager {
4156
+ export class GuildEmojiManager extends CachedManager<Snowflake, GuildEmoji, EmojiResolvable> {
4146
4157
  private constructor(guild: Guild, iterable?: Iterable<RawGuildEmojiData>);
4147
4158
  public guild: Guild;
4148
4159
  public create(options: GuildEmojiCreateOptions): Promise<GuildEmoji>;
@@ -4151,6 +4162,7 @@ export class GuildEmojiManager extends BaseGuildEmojiManager {
4151
4162
  public fetchAuthor(emoji: EmojiResolvable): Promise<User>;
4152
4163
  public delete(emoji: EmojiResolvable, reason?: string): Promise<void>;
4153
4164
  public edit(emoji: EmojiResolvable, options: GuildEmojiEditOptions): Promise<GuildEmoji>;
4165
+ public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null;
4154
4166
  }
4155
4167
 
4156
4168
  export class GuildEmojiRoleManager extends DataManager<Snowflake, Role, RoleResolvable> {
@@ -4574,7 +4586,9 @@ export type AllowedPartial =
4574
4586
  | Message
4575
4587
  | MessageReaction
4576
4588
  | GuildScheduledEvent
4577
- | ThreadMember;
4589
+ | ThreadMember
4590
+ | Poll
4591
+ | PollAnswer;
4578
4592
 
4579
4593
  export type AllowedThreadTypeForAnnouncementChannel = ChannelType.AnnouncementThread;
4580
4594
 
@@ -4969,7 +4983,6 @@ export interface Caches {
4969
4983
  ApplicationCommandManager: [manager: typeof ApplicationCommandManager, holds: typeof ApplicationCommand];
4970
4984
  ApplicationEmojiManager: [manager: typeof ApplicationEmojiManager, holds: typeof ApplicationEmoji];
4971
4985
  AutoModerationRuleManager: [manager: typeof AutoModerationRuleManager, holds: typeof AutoModerationRule];
4972
- BaseGuildEmojiManager: [manager: typeof BaseGuildEmojiManager, holds: typeof GuildEmoji];
4973
4986
  // TODO: ChannelManager: [manager: typeof ChannelManager, holds: typeof Channel];
4974
4987
  DMMessageManager: [manager: typeof MessageManager, holds: typeof Message<false>];
4975
4988
  EntitlementManager: [manager: typeof EntitlementManager, holds: typeof Entitlement];
@@ -5126,8 +5139,8 @@ export interface ClientEventTypes {
5126
5139
  inviteDelete: [invite: Invite];
5127
5140
  messageCreate: [message: OmitPartialGroupDMChannel<Message>];
5128
5141
  messageDelete: [message: OmitPartialGroupDMChannel<Message | PartialMessage>];
5129
- messagePollVoteAdd: [pollAnswer: PollAnswer, userId: Snowflake];
5130
- messagePollVoteRemove: [pollAnswer: PollAnswer, userId: Snowflake];
5142
+ messagePollVoteAdd: [pollAnswer: PollAnswer | PartialPollAnswer, userId: Snowflake];
5143
+ messagePollVoteRemove: [pollAnswer: PollAnswer | PartialPollAnswer, userId: Snowflake];
5131
5144
  messageReactionRemoveAll: [
5132
5145
  message: OmitPartialGroupDMChannel<Message | PartialMessage>,
5133
5146
  reactions: ReadonlyCollection<string | Snowflake, MessageReaction>,
@@ -6539,6 +6552,23 @@ export interface PartialMessage
6539
6552
 
6540
6553
  export interface PartialMessageReaction extends Partialize<MessageReaction, 'count'> {}
6541
6554
 
6555
+ export interface PartialPoll
6556
+ extends Partialize<
6557
+ Poll,
6558
+ 'allowMultiselect' | 'layoutType' | 'expiresTimestamp',
6559
+ null,
6560
+ 'question' | 'message' | 'answers'
6561
+ > {
6562
+ question: { text: null };
6563
+ message: PartialMessage;
6564
+ // eslint-disable-next-line no-restricted-syntax
6565
+ answers: Collection<number, PartialPollAnswer>;
6566
+ }
6567
+
6568
+ export interface PartialPollAnswer extends Partialize<PollAnswer, 'emoji' | 'text', null, 'poll'> {
6569
+ readonly poll: PartialPoll;
6570
+ }
6571
+
6542
6572
  export interface PartialGuildScheduledEvent
6543
6573
  extends Partialize<GuildScheduledEvent, 'userCount', 'status' | 'privacyLevel' | 'name' | 'entityType'> {}
6544
6574
 
@@ -6563,6 +6593,8 @@ export enum Partials {
6563
6593
  Reaction,
6564
6594
  GuildScheduledEvent,
6565
6595
  ThreadMember,
6596
+ Poll,
6597
+ PollAnswer,
6566
6598
  }
6567
6599
 
6568
6600
  export interface PartialUser extends Partialize<User, 'username' | 'tag' | 'discriminator'> {}
@@ -214,6 +214,10 @@ import {
214
214
  InteractionCallbackResponse,
215
215
  GuildScheduledEventRecurrenceRuleOptions,
216
216
  ThreadOnlyChannel,
217
+ PartialPoll,
218
+ PartialPollAnswer,
219
+ PollAnswer,
220
+ PollAnswerVoterManager,
217
221
  } from './index.js';
218
222
  import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
219
223
  import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
@@ -656,6 +660,48 @@ client.on('messageDeleteBulk', (messages, { client }) => {
656
660
  expectType<Client<true>>(client);
657
661
  });
658
662
 
663
+ client.on('messagePollVoteAdd', async (answer, userId) => {
664
+ expectType<Client<true>>(answer.client);
665
+ expectType<Snowflake>(userId);
666
+
667
+ if (answer.partial) {
668
+ expectType<null>(answer.emoji);
669
+ expectType<null>(answer.text);
670
+ expectNotType<null>(answer.id);
671
+ expectNotType<null>(answer.poll);
672
+
673
+ await answer.poll.fetch();
674
+ answer = answer.poll.answers?.get(answer.id) ?? answer;
675
+
676
+ expectType<User>(answer.voters.cache.get(userId)!);
677
+ }
678
+
679
+ expectType<string | null>(answer.text);
680
+ expectType<GuildEmoji | Emoji | null>(answer.emoji);
681
+ expectType<number>(answer.id);
682
+ expectType<number>(answer.voteCount!);
683
+ });
684
+
685
+ client.on('messagePollVoteRemove', async (answer, userId) => {
686
+ expectType<Client<true>>(answer.client);
687
+ expectType<Snowflake>(userId);
688
+
689
+ if (answer.partial) {
690
+ expectType<null>(answer.emoji);
691
+ expectType<null>(answer.text);
692
+ expectNotType<null>(answer.id);
693
+ expectNotType<null>(answer.poll);
694
+
695
+ await answer.poll.fetch();
696
+ answer = answer.poll.answers?.get(answer.id) ?? answer;
697
+ }
698
+
699
+ expectType<string | null>(answer.text);
700
+ expectType<GuildEmoji | Emoji | null>(answer.emoji);
701
+ expectType<number>(answer.id);
702
+ expectType<number>(answer.voteCount!);
703
+ });
704
+
659
705
  client.on('messageReactionAdd', async (reaction, { client }) => {
660
706
  expectType<Client<true>>(reaction.client);
661
707
  expectType<Client<true>>(client);
@@ -1724,6 +1770,12 @@ declare const messageManager: MessageManager;
1724
1770
  messageManager.fetch({ message: '1234567890', after: '1234567890', cache: true, force: false });
1725
1771
  }
1726
1772
 
1773
+ declare const pollAnswerVoterManager: PollAnswerVoterManager;
1774
+ {
1775
+ expectType<Promise<Collection<Snowflake, User>>>(pollAnswerVoterManager.fetch());
1776
+ expectType<PollAnswer>(pollAnswerVoterManager.answer);
1777
+ }
1778
+
1727
1779
  declare const roleManager: RoleManager;
1728
1780
  expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch());
1729
1781
  expectType<Promise<Collection<Snowflake, Role>>>(roleManager.fetch(undefined, {}));
@@ -2663,16 +2715,42 @@ await textChannel.send({
2663
2715
  },
2664
2716
  });
2665
2717
 
2718
+ declare const partialPoll: PartialPoll;
2719
+ {
2720
+ if (partialPoll.partial) {
2721
+ expectType<null>(partialPoll.question.text);
2722
+ expectType<PartialMessage>(partialPoll.message);
2723
+ expectType<null>(partialPoll.allowMultiselect);
2724
+ expectType<null>(partialPoll.layoutType);
2725
+ expectType<null>(partialPoll.expiresTimestamp);
2726
+ expectType<Collection<number, PartialPollAnswer>>(partialPoll.answers);
2727
+ }
2728
+ }
2729
+
2730
+ declare const partialPollAnswer: PartialPollAnswer;
2731
+ {
2732
+ if (partialPollAnswer.partial) {
2733
+ expectType<PartialPoll>(partialPollAnswer.poll);
2734
+ expectType<null>(partialPollAnswer.emoji);
2735
+ expectType<null>(partialPollAnswer.text);
2736
+ }
2737
+ }
2666
2738
  declare const poll: Poll;
2667
2739
  declare const message: Message;
2668
2740
  declare const pollData: PollData;
2669
2741
  {
2670
2742
  expectType<Message>(await poll.end());
2743
+ expectType<false>(poll.partial);
2744
+ expectNotType<Collection<number, PartialPollAnswer>>(poll.answers);
2671
2745
 
2672
2746
  const answer = poll.answers.first()!;
2673
- expectType<number>(answer.voteCount);
2674
2747
 
2675
- expectType<Collection<Snowflake, User>>(await answer.fetchVoters({ after: snowflake, limit: 10 }));
2748
+ if (!answer.partial) {
2749
+ expectType<number>(answer.voteCount);
2750
+ expectType<number>(answer.id);
2751
+ expectType<PollAnswerVoterManager>(answer.voters);
2752
+ expectType<Collection<Snowflake, User>>(await answer.voters.fetch({ after: snowflake, limit: 10 }));
2753
+ }
2676
2754
 
2677
2755
  await messageManager.endPoll(snowflake);
2678
2756
  await messageManager.fetchPollAnswerVoters({
@@ -1,85 +0,0 @@
1
- 'use strict';
2
-
3
- const { CachedManager } = require('./CachedManager.js');
4
- const { ApplicationEmoji } = require('../structures/ApplicationEmoji.js');
5
- const { GuildEmoji } = require('../structures/GuildEmoji.js');
6
- const { ReactionEmoji } = require('../structures/ReactionEmoji.js');
7
- const { parseEmoji } = require('../util/Util.js');
8
-
9
- /**
10
- * Holds methods to resolve GuildEmojis and stores their cache.
11
- * @extends {CachedManager}
12
- */
13
- class BaseGuildEmojiManager extends CachedManager {
14
- constructor(client, iterable) {
15
- super(client, GuildEmoji, iterable);
16
- }
17
-
18
- /**
19
- * The cache of GuildEmojis
20
- * @type {Collection<Snowflake, GuildEmoji>}
21
- * @name BaseGuildEmojiManager#cache
22
- */
23
-
24
- /**
25
- * Data that can be resolved into a GuildEmoji object. This can be:
26
- * * A Snowflake
27
- * * A GuildEmoji object
28
- * * A ReactionEmoji object
29
- * * An ApplicationEmoji object
30
- * @typedef {Snowflake|GuildEmoji|ReactionEmoji|ApplicationEmoji} EmojiResolvable
31
- */
32
-
33
- /**
34
- * Resolves an EmojiResolvable to an Emoji object.
35
- * @param {EmojiResolvable} emoji The Emoji resolvable to identify
36
- * @returns {?GuildEmoji}
37
- */
38
- resolve(emoji) {
39
- if (emoji instanceof ReactionEmoji) return super.cache.get(emoji.id) ?? null;
40
- if (emoji instanceof ApplicationEmoji) return super.cache.get(emoji.id) ?? null;
41
- return super.resolve(emoji);
42
- }
43
-
44
- /**
45
- * Resolves an EmojiResolvable to an Emoji id string.
46
- * @param {EmojiResolvable} emoji The Emoji resolvable to identify
47
- * @returns {?Snowflake}
48
- */
49
- resolveId(emoji) {
50
- if (emoji instanceof ReactionEmoji) return emoji.id;
51
- if (emoji instanceof ApplicationEmoji) return emoji.id;
52
- return super.resolveId(emoji);
53
- }
54
-
55
- /**
56
- * Data that can be resolved to give an emoji identifier. This can be:
57
- * * An EmojiResolvable
58
- * * The `<a:name:id>`, `<:name:id>`, `a:name:id` or `name:id` emoji identifier string of an emoji
59
- * * The Unicode representation of an emoji
60
- * @typedef {string|EmojiResolvable} EmojiIdentifierResolvable
61
- */
62
-
63
- /**
64
- * Resolves an EmojiResolvable to an emoji identifier.
65
- * @param {EmojiIdentifierResolvable} emoji The emoji resolvable to resolve
66
- * @returns {?string}
67
- */
68
- resolveIdentifier(emoji) {
69
- const emojiResolvable = this.resolve(emoji);
70
- if (emojiResolvable) return emojiResolvable.identifier;
71
- if (emoji instanceof ReactionEmoji) return emoji.identifier;
72
- if (emoji instanceof ApplicationEmoji) return emoji.identifier;
73
- if (typeof emoji === 'string') {
74
- const res = parseEmoji(emoji);
75
- if (res?.name.length) {
76
- emoji = `${res.animated ? 'a:' : ''}${res.name}${res.id ? `:${res.id}` : ''}`;
77
- }
78
- if (!emoji.includes('%')) return encodeURIComponent(emoji);
79
- return emoji;
80
- }
81
- return null;
82
- }
83
- }
84
-
85
- exports.BaseGuildEmojiManager = BaseGuildEmojiManager;