rockcord 4.0.0-dev.5 → 4.0.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.
Files changed (65) hide show
  1. package/README.md +4 -3
  2. package/package.json +15 -12
  3. package/src/client/Client.js +3 -3
  4. package/src/client/WebhookClient.js +1 -1
  5. package/src/client/actions/VoiceStateUpdate.js +2 -2
  6. package/src/client/voice/VoiceConnection.js +2 -2
  7. package/src/client/voice/dispatcher/AudioDispatcher.js +1 -1
  8. package/src/client/voice/dispatcher/BaseDispatcher.js +37 -12
  9. package/src/client/voice/dispatcher/VideoDispatcher.js +83 -0
  10. package/src/client/voice/networking/CongestionControl.js +84 -0
  11. package/src/client/voice/networking/DAVE.js +26 -1
  12. package/src/client/voice/networking/MediaRecovery.js +112 -9
  13. package/src/client/voice/player/MediaPlayer.js +18 -3
  14. package/src/client/voice/player/processing/AnnexBNalSplitter.js +0 -1
  15. package/src/client/voice/receiver/AudioJitter.js +7 -4
  16. package/src/client/voice/receiver/PacketHandler.js +10 -4
  17. package/src/client/voice/receiver/Receiver.js +5 -3
  18. package/src/client/voice/receiver/Recorder.js +44 -14
  19. package/src/client/voice/util/PlayInterface.js +2 -0
  20. package/src/client/voice/util/Secretbox.js +1 -1
  21. package/src/client/websocket/WebSocketShard.js +0 -1
  22. package/src/managers/ApplicationCommandManager.js +0 -2
  23. package/src/managers/ApplicationCommandPermissionsManager.js +0 -1
  24. package/src/managers/GuildChannelManager.js +2 -3
  25. package/src/managers/GuildMemberManager.js +0 -1
  26. package/src/managers/GuildTextThreadManager.js +1 -1
  27. package/src/managers/MessageManager.js +5 -5
  28. package/src/managers/RoleManager.js +1 -1
  29. package/src/rest/APIRequest.js +0 -1
  30. package/src/rest/APIRouter.js +2 -2
  31. package/src/rest/DiscordAPIError.js +1 -1
  32. package/src/rest/RequestHandler.js +3 -3
  33. package/src/sharding/ShardingManager.js +2 -2
  34. package/src/structures/ApplicationCommand.js +2 -7
  35. package/src/structures/BaseCommandInteraction.js +1 -2
  36. package/src/structures/BaseGuildTextChannel.js +1 -1
  37. package/src/structures/BaseGuildVoiceChannel.js +1 -1
  38. package/src/structures/ClientPresence.js +0 -1
  39. package/src/structures/ClientUser.js +13 -5
  40. package/src/structures/ContainerComponent.js +1 -1
  41. package/src/structures/DMChannel.js +1 -1
  42. package/src/structures/GroupDMChannel.js +4 -4
  43. package/src/structures/Guild.js +0 -2
  44. package/src/structures/GuildAuditLogs.js +4 -4
  45. package/src/structures/GuildScheduledEvent.js +0 -2
  46. package/src/structures/Interaction.js +1 -1
  47. package/src/structures/InteractionCollector.js +2 -2
  48. package/src/structures/InteractionWebhook.js +0 -1
  49. package/src/structures/Message.js +16 -17
  50. package/src/structures/MessageComponentInteraction.js +1 -1
  51. package/src/structures/MessageEmbed.js +0 -2
  52. package/src/structures/MessagePayload.js +2 -2
  53. package/src/structures/ModalSubmitInteraction.js +2 -2
  54. package/src/structures/ThreadChannel.js +3 -3
  55. package/src/structures/ThreadOnlyChannel.js +1 -1
  56. package/src/structures/WebEmbed.js +0 -1
  57. package/src/structures/interfaces/Application.js +2 -2
  58. package/src/structures/interfaces/Collector.js +1 -4
  59. package/src/structures/interfaces/TextBasedChannel.js +6 -6
  60. package/src/util/AttachmentFlags.js +0 -1
  61. package/src/util/Constants.js +0 -2
  62. package/src/util/Options.js +3 -3
  63. package/src/util/Util.js +1 -2
  64. package/typings/index.d.ts +108 -115
  65. package/typings/rawDataTypes.d.ts +5 -15
@@ -203,7 +203,7 @@ class DMChannel extends Channel {
203
203
  }
204
204
 
205
205
  // These are here only for documentation purposes - they are implemented by TextBasedChannel
206
- /* eslint-disable no-empty-function */
206
+
207
207
  get lastMessage() {}
208
208
  get lastPinAt() {}
209
209
  send() {}
@@ -290,9 +290,9 @@ class GroupDMChannel extends Channel {
290
290
  async removeInvite(invite) {
291
291
  // Resolve
292
292
  let code = invite?.code;
293
- if (!code && URL.canParse(invite)) code = new URL(invite).pathname.slice(1);
294
- else code = invite;
295
- await this.client.api.channels(this.id).invites[invite].delete();
293
+ if (!code) code = typeof invite === 'string' && URL.canParse(invite) ? new URL(invite).pathname.slice(1) : invite;
294
+ if (typeof code !== 'string' || !code) throw new TypeError('Invalid invite');
295
+ await this.client.api.channels(this.id).invites[code].delete();
296
296
  return this;
297
297
  }
298
298
 
@@ -373,7 +373,7 @@ class GroupDMChannel extends Channel {
373
373
  }
374
374
 
375
375
  // These are here only for documentation purposes - they are implemented by TextBasedChannel
376
- /* eslint-disable no-empty-function */
376
+
377
377
  get lastMessage() {}
378
378
  get lastPinAt() {}
379
379
  send() {}
@@ -1062,7 +1062,6 @@ class Guild extends AnonymousGuild {
1062
1062
  return this.edit({ explicitContentFilter }, reason);
1063
1063
  }
1064
1064
 
1065
- /* eslint-disable max-len */
1066
1065
  /**
1067
1066
  * Edits the setting of the default message notifications of the guild.
1068
1067
  * @param {?(DefaultMessageNotificationLevel|number)} defaultMessageNotifications The new default message notification level of the guild
@@ -1072,7 +1071,6 @@ class Guild extends AnonymousGuild {
1072
1071
  setDefaultMessageNotifications(defaultMessageNotifications, reason) {
1073
1072
  return this.edit({ defaultMessageNotifications }, reason);
1074
1073
  }
1075
- /* eslint-enable max-len */
1076
1074
 
1077
1075
  /**
1078
1076
  * Edits the flags of the default message notifications of the guild.
@@ -449,7 +449,7 @@ class GuildAuditLogsEntry {
449
449
  this.executor = data.user_id
450
450
  ? guild.client.options.partials.includes(PartialTypes.USER)
451
451
  ? guild.client.users._add({ id: data.user_id })
452
- : guild.client.users.cache.get(data.user_id) ?? null
452
+ : (guild.client.users.cache.get(data.user_id) ?? null)
453
453
  : null;
454
454
 
455
455
  /**
@@ -582,7 +582,7 @@ class GuildAuditLogsEntry {
582
582
  } else if (targetType === Targets.USER && data.target_id) {
583
583
  this.target = guild.client.options.partials.includes(PartialTypes.USER)
584
584
  ? guild.client.users._add({ id: data.target_id })
585
- : guild.client.users.cache.get(data.target_id) ?? null;
585
+ : (guild.client.users.cache.get(data.target_id) ?? null);
586
586
  } else if (targetType === Targets.GUILD) {
587
587
  this.target = guild.client.guilds.cache.get(data.target_id);
588
588
  } else if (targetType === Targets.WEBHOOK) {
@@ -621,8 +621,8 @@ class GuildAuditLogsEntry {
621
621
  // Discord sends a channel id for the MESSAGE_BULK_DELETE action type.
622
622
  this.target =
623
623
  data.action_type === Actions.MESSAGE_BULK_DELETE
624
- ? guild.channels.cache.get(data.target_id) ?? { id: data.target_id }
625
- : guild.client.users.cache.get(data.target_id) ?? null;
624
+ ? (guild.channels.cache.get(data.target_id) ?? { id: data.target_id })
625
+ : (guild.client.users.cache.get(data.target_id) ?? null);
626
626
  } else if (targetType === Targets.INTEGRATION) {
627
627
  this.target =
628
628
  logs?.integrations.get(data.target_id) ??
@@ -160,14 +160,12 @@ class GuildScheduledEvent extends Base {
160
160
  this.creator ??= this.client.users.resolve(this.creatorId);
161
161
  }
162
162
 
163
- /* eslint-disable max-len */
164
163
  /**
165
164
  * Represents the additional metadata for a {@link GuildScheduledEvent}
166
165
  * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata}
167
166
  * @typedef {Object} GuildScheduledEventEntityMetadata
168
167
  * @property {?string} location The location of the guild scheduled event
169
168
  */
170
- /* eslint-enable max-len */
171
169
 
172
170
  if ('entity_metadata' in data) {
173
171
  if (data.entity_metadata) {
@@ -61,7 +61,7 @@ class Interaction extends Base {
61
61
  * If this interaction was sent in a guild, the member which sent it
62
62
  * @type {?(GuildMember|APIGuildMember)}
63
63
  */
64
- this.member = data.member ? this.guild?.members._add(data.member) ?? data.member : null;
64
+ this.member = data.member ? (this.guild?.members._add(data.member) ?? data.member) : null;
65
65
 
66
66
  /**
67
67
  * The version
@@ -67,7 +67,7 @@ class InteractionCollector extends Collector {
67
67
  this.interactionType =
68
68
  typeof options.interactionType === 'number'
69
69
  ? InteractionTypes[options.interactionType]
70
- : options.interactionType ?? null;
70
+ : (options.interactionType ?? null);
71
71
 
72
72
  /**
73
73
  * The type of component to collect
@@ -76,7 +76,7 @@ class InteractionCollector extends Collector {
76
76
  this.componentType =
77
77
  typeof options.componentType === 'number'
78
78
  ? MessageComponentTypes[options.componentType]
79
- : options.componentType ?? null;
79
+ : (options.componentType ?? null);
80
80
 
81
81
  /**
82
82
  * The users that have interacted with this collector
@@ -25,7 +25,6 @@ class InteractionWebhook {
25
25
  }
26
26
 
27
27
  // These are here only for documentation purposes - they are implemented by Webhook
28
- /* eslint-disable no-empty-function, valid-jsdoc */
29
28
  /**
30
29
  * Sends a message with this webhook.
31
30
  * @param {string|MessagePayload|InteractionReplyOptions} options The content for the reply
@@ -549,7 +549,6 @@ class Message extends Base {
549
549
  * @readonly
550
550
  */
551
551
  get cleanContent() {
552
- // eslint-disable-next-line eqeqeq
553
552
  return this.content != null && this.channel ? Util.cleanContent(this.content, this.channel) : null;
554
553
  }
555
554
 
@@ -604,9 +603,9 @@ class Message extends Base {
604
603
  get editable() {
605
604
  const precheck = Boolean(
606
605
  this.author.id === this.client.user.id &&
607
- !deletedMessages.has(this) &&
608
- (!this.guild || this.channel?.viewable) &&
609
- this.reference?.type !== 'FORWARD',
606
+ !deletedMessages.has(this) &&
607
+ (!this.guild || this.channel?.viewable) &&
608
+ this.reference?.type !== 'FORWARD',
610
609
  );
611
610
 
612
611
  // Regardless of permissions thread messages cannot be edited if
@@ -646,8 +645,8 @@ class Message extends Base {
646
645
 
647
646
  return Boolean(
648
647
  this.author.id === this.client.user.id ||
649
- (permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) &&
650
- this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()),
648
+ (permissions.has(Permissions.FLAGS.MANAGE_MESSAGES, false) &&
649
+ this.guild.members.me.communicationDisabledUntilTimestamp < Date.now()),
651
650
  );
652
651
  }
653
652
 
@@ -672,10 +671,10 @@ class Message extends Base {
672
671
  const { channel } = this;
673
672
  return Boolean(
674
673
  !this.system &&
675
- !deletedMessages.has(this) &&
676
- (!this.guild ||
677
- (channel?.viewable &&
678
- channel?.permissionsFor(this.client.user)?.has(Permissions.FLAGS.MANAGE_MESSAGES, false))),
674
+ !deletedMessages.has(this) &&
675
+ (!this.guild ||
676
+ (channel?.viewable &&
677
+ channel?.permissionsFor(this.client.user)?.has(Permissions.FLAGS.MANAGE_MESSAGES, false))),
679
678
  );
680
679
  }
681
680
 
@@ -705,13 +704,13 @@ class Message extends Base {
705
704
  const { channel } = this;
706
705
  return Boolean(
707
706
  channel?.type === 'GUILD_NEWS' &&
708
- !this.flags.has(MessageFlags.FLAGS.CROSSPOSTED) &&
709
- this.reference?.type !== 'FORWARD' &&
710
- this.type === 'DEFAULT' &&
711
- !this.poll &&
712
- channel.viewable &&
713
- channel.permissionsFor(this.client.user)?.has(bitfield, false) &&
714
- !deletedMessages.has(this),
707
+ !this.flags.has(MessageFlags.FLAGS.CROSSPOSTED) &&
708
+ this.reference?.type !== 'FORWARD' &&
709
+ this.type === 'DEFAULT' &&
710
+ !this.poll &&
711
+ channel.viewable &&
712
+ channel.permissionsFor(this.client.user)?.has(bitfield, false) &&
713
+ !deletedMessages.has(this),
715
714
  );
716
715
  }
717
716
 
@@ -92,7 +92,7 @@ class MessageComponentInteraction extends Interaction {
92
92
  }
93
93
 
94
94
  // These are here only for documentation purposes - they are implemented by InteractionResponses
95
- /* eslint-disable no-empty-function */
95
+
96
96
  deferReply() {}
97
97
  reply() {}
98
98
  fetchReply() {}
@@ -37,7 +37,6 @@ class MessageEmbed {
37
37
  * @property {Partial<MessageEmbedFooter>} [footer] The footer of this embed
38
38
  */
39
39
 
40
- // eslint-disable-next-line valid-jsdoc
41
40
  /**
42
41
  * @param {MessageEmbed|MessageEmbedOptions|APIEmbed} [data={}] MessageEmbed to clone or raw embed data
43
42
  */
@@ -320,7 +319,6 @@ class MessageEmbed {
320
319
  addField(name, value, inline) {
321
320
  if (!deprecationEmittedForAddField) {
322
321
  process.emitWarning(
323
- // eslint-disable-next-line max-len
324
322
  'MessageEmbed#addField is deprecated and will be removed in the next major update. Use MessageEmbed#addFields instead.',
325
323
  'DeprecationWarning',
326
324
  );
@@ -135,7 +135,7 @@ class MessagePayload {
135
135
  let nonce = SnowflakeUtil.generate();
136
136
  if (typeof this.options.nonce !== 'undefined') {
137
137
  nonce = this.options.nonce;
138
- // eslint-disable-next-line max-len
138
+
139
139
  if (typeof nonce === 'number' ? !Number.isInteger(nonce) : typeof nonce !== 'string') {
140
140
  throw new RangeError('MESSAGE_NONCE_TYPE');
141
141
  }
@@ -177,7 +177,7 @@ class MessagePayload {
177
177
  let message_reference;
178
178
  if (typeof this.options.reply === 'object') {
179
179
  const reference = this.options.reply.messageReference;
180
- const message_id = this.isMessage ? reference.id ?? reference : this.target.messages.resolveId(reference);
180
+ const message_id = this.isMessage ? (reference.id ?? reference) : this.target.messages.resolveId(reference);
181
181
  if (message_id) {
182
182
  message_reference = {
183
183
  message_id,
@@ -48,7 +48,7 @@ class ModalSubmitInteraction extends Interaction {
48
48
  * The message associated with this interaction
49
49
  * @type {Message|APIMessage|null}
50
50
  */
51
- this.message = data.message ? this.channel?.messages._add(data.message) ?? data.message : null;
51
+ this.message = data.message ? (this.channel?.messages._add(data.message) ?? data.message) : null;
52
52
 
53
53
  /**
54
54
  * The fields within the modal
@@ -103,7 +103,7 @@ class ModalSubmitInteraction extends Interaction {
103
103
  }
104
104
 
105
105
  // These are here only for documentation purposes - they are implemented by InteractionResponses
106
- /* eslint-disable no-empty-function */
106
+
107
107
  deferReply() {}
108
108
  reply() {}
109
109
  fetchReply() {}
@@ -87,7 +87,7 @@ class ThreadChannel extends Channel {
87
87
  * <info>Always `null` in public threads</info>
88
88
  * @type {?boolean}
89
89
  */
90
- this.invitable = this.type === 'GUILD_PRIVATE_THREAD' ? data.thread_metadata.invitable ?? false : null;
90
+ this.invitable = this.type === 'GUILD_PRIVATE_THREAD' ? (data.thread_metadata.invitable ?? false) : null;
91
91
 
92
92
  /**
93
93
  * Whether the thread is archived
@@ -305,7 +305,7 @@ class ThreadChannel extends Channel {
305
305
  * @param {BaseFetchOptions} [options] Additional options for this fetch
306
306
  * @returns {Promise<Message|null>}
307
307
  */
308
- // eslint-disable-next-line require-await
308
+
309
309
  async fetchStarterMessage(options) {
310
310
  const channel = this.parent?.type === 'GUILD_FORUM' ? this : this.parent;
311
311
  return channel?.messages.fetch(this.id, options) ?? null;
@@ -589,7 +589,7 @@ class ThreadChannel extends Channel {
589
589
  }
590
590
 
591
591
  // These are here only for documentation purposes - they are implemented by TextBasedChannel
592
- /* eslint-disable no-empty-function */
592
+
593
593
  get lastMessage() {}
594
594
  get lastPinAt() {}
595
595
  send() {}
@@ -227,7 +227,7 @@ class ThreadOnlyChannel extends GuildChannel {
227
227
  }
228
228
 
229
229
  // These are here only for documentation purposes - they are implemented by TextBasedChannel
230
- /* eslint-disable no-empty-function */
230
+
231
231
  createWebhook() {}
232
232
  fetchWebhooks() {}
233
233
  setNSFW() {}
@@ -42,7 +42,6 @@ class WebEmbed {
42
42
  * @property {string} [redirect] Redirect URL
43
43
  */
44
44
 
45
- // eslint-disable-next-line valid-jsdoc
46
45
  /**
47
46
  * @param {WebEmbed|WebEmbedOptions|APIEmbed} [data={}] WebEmbed to clone or raw embed data
48
47
  */
@@ -207,8 +207,8 @@ class Application extends Base {
207
207
  this.owner = data.team
208
208
  ? new Team(this.client, data.team)
209
209
  : data.owner
210
- ? this.client.users._add(data.owner)
211
- : this.owner ?? null;
210
+ ? this.client.users._add(data.owner)
211
+ : (this.owner ?? null);
212
212
 
213
213
  if ('splash' in data) {
214
214
  /**
@@ -164,7 +164,7 @@ class Collector extends EventEmitter {
164
164
 
165
165
  const onEnd = () => {
166
166
  cleanup();
167
- reject(this.collected); // eslint-disable-line prefer-promise-reject-errors
167
+ reject(this.collected);
168
168
  };
169
169
 
170
170
  this.on('collect', onCollect);
@@ -246,7 +246,6 @@ class Collector extends EventEmitter {
246
246
  if (queue.length) {
247
247
  yield queue.shift();
248
248
  } else {
249
- // eslint-disable-next-line no-await-in-loop
250
249
  await new Promise(resolve => {
251
250
  const tick = () => {
252
251
  this.removeListener('collect', tick);
@@ -267,7 +266,6 @@ class Collector extends EventEmitter {
267
266
  return Util.flatten(this);
268
267
  }
269
268
 
270
- /* eslint-disable no-empty-function */
271
269
  /**
272
270
  * The reason this collector has ended with, or null if it hasn't ended yet
273
271
  * @type {?string}
@@ -295,7 +293,6 @@ class Collector extends EventEmitter {
295
293
  * @abstract
296
294
  */
297
295
  dispose() {}
298
- /* eslint-enable no-empty-function */
299
296
  }
300
297
 
301
298
  module.exports = Collector;
@@ -1,14 +1,10 @@
1
1
  'use strict';
2
2
 
3
- /* eslint-disable import/order */
3
+ /* eslint-disable import-x/order */
4
4
  const MessageCollector = require('../MessageCollector');
5
- const MessagePayload = require('../MessagePayload');
6
- const { InteractionTypes, ApplicationCommandOptionTypes, Events } = require('../../util/Constants');
7
- const { Error } = require('../../errors');
8
- const SnowflakeUtil = require('../../util/SnowflakeUtil');
9
5
  const { setTimeout } = require('node:timers');
10
6
  const { s } = require('@sapphire/shapeshift');
11
- const Util = require('../../util/Util');
7
+ const { Error } = require('../../errors');
12
8
  const validateName = stringName =>
13
9
  s
14
10
  .string()
@@ -519,6 +515,10 @@ module.exports = TextBasedChannel;
519
515
 
520
516
  // Fixes Circular
521
517
  const MessageManager = require('../../managers/MessageManager');
518
+ const { InteractionTypes, ApplicationCommandOptionTypes, Events } = require('../../util/Constants');
519
+ const SnowflakeUtil = require('../../util/SnowflakeUtil');
520
+ const Util = require('../../util/Util');
521
+ const MessagePayload = require('../MessagePayload');
522
522
 
523
523
  // Utils
524
524
  function parseChoices(parent, list_choices, value) {
@@ -15,7 +15,6 @@ class AttachmentFlags extends BitField {}
15
15
  * @param {BitFieldResolvable} [bits=0] Bit(s) to read from
16
16
  */
17
17
 
18
- /* eslint-disable max-len */
19
18
  /**
20
19
  * Numeric guild member flags. All available properties:
21
20
  * * `IS_REMIX`
@@ -1456,7 +1456,6 @@ exports.StickerFormatTypes = createEnum([null, 'PNG', 'APNG', 'LOTTIE', 'GIF']);
1456
1456
  */
1457
1457
  exports.OverwriteTypes = createEnum(['role', 'member']);
1458
1458
 
1459
- /* eslint-disable max-len */
1460
1459
  /**
1461
1460
  * The type of an {@link ApplicationCommand} object:
1462
1461
  * * CHAT_INPUT
@@ -1763,7 +1762,6 @@ exports.GuildScheduledEventStatuses = createEnum([null, 'SCHEDULED', 'ACTIVE', '
1763
1762
  * @see {@link https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types}
1764
1763
  */
1765
1764
  exports.GuildScheduledEventEntityTypes = createEnum([null, 'STAGE_INSTANCE', 'VOICE', 'EXTERNAL']);
1766
- /* eslint-enable max-len */
1767
1765
 
1768
1766
  /**
1769
1767
  * The camera video quality mode of a {@link VoiceChannel}:
@@ -276,7 +276,7 @@ class Options extends null {
276
276
 
277
277
  return manager => {
278
278
  const setting = settings[manager.name];
279
- /* eslint-disable-next-line eqeqeq */
279
+
280
280
  if (setting == null) {
281
281
  return new Collection();
282
282
  }
@@ -286,14 +286,14 @@ class Options extends null {
286
286
  }
287
287
  return new LimitedCollection({ maxSize: setting });
288
288
  }
289
- /* eslint-disable eqeqeq */
289
+
290
290
  const noSweeping =
291
291
  setting.sweepFilter == null ||
292
292
  setting.sweepInterval == null ||
293
293
  setting.sweepInterval <= 0 ||
294
294
  setting.sweepInterval === Infinity;
295
295
  const noLimit = setting.maxSize == null || setting.maxSize === Infinity;
296
- /* eslint-enable eqeqeq */
296
+
297
297
  if (noSweeping && noLimit) {
298
298
  return new Collection();
299
299
  }
package/src/util/Util.js CHANGED
@@ -710,7 +710,6 @@ class Util extends null {
710
710
  static resolveAutoArchiveMaxLimit() {
711
711
  if (!deprecationEmittedForResolveAutoArchiveMaxLimit) {
712
712
  process.emitWarning(
713
- // eslint-disable-next-line max-len
714
713
  "The Util.resolveAutoArchiveMaxLimit method and the 'MAX' option are deprecated and will be removed in the next major version.",
715
714
  'DeprecationWarning',
716
715
  );
@@ -731,7 +730,7 @@ class Util extends null {
731
730
  name: tag.name,
732
731
  moderated: tag.moderated,
733
732
  emoji:
734
- tag.emoji_id ?? tag.emoji_name
733
+ (tag.emoji_id ?? tag.emoji_name)
735
734
  ? {
736
735
  id: tag.emoji_id,
737
736
  name: tag.emoji_name,