fix(transformers): message transformer using different style (#2916)

* fix(transformers): message transformer using different style

* fix: more bench tests

* fix(bench): token can not be empty

* more desired props

* fix: bug on message.id props

* fix: transfomrer errors on bench

---------

Co-authored-by: Jonathan Ho <heiheiho000@gmail.com>
This commit is contained in:
Skillz4Killz
2023-04-01 21:26:46 -05:00
committed by GitHub
co-authored by Jonathan Ho
parent 782a778a1d
commit dea9d1d152
7 changed files with 1583 additions and 91 deletions
@@ -0,0 +1,753 @@
import {
ApplicationFlags,
ButtonStyles,
iconHashToBigInt,
InteractionTypes,
MessageActivityTypes,
MessageComponentTypes,
MessageTypes,
PremiumTypes,
StickerFormatTypes,
TeamMembershipStates,
TextStyles,
UserFlags,
type Bot,
type DiscordMessage,
} from '@discordeno/bot'
import { MemberToggles } from '@discordeno/bot/dist/transformers/index.js'
import { createBot } from '../../../bot/dist/index.js'
import { memoryBenchmark } from '../utils/memoryBenchmark.js'
export const CHANNEL_MENTION_REGEX = /<#[0-9]+>/g
const MESSAGE_SIZE = 20000
const bot = createBot({
token: process.env.DISCORD_TOKEN ?? " ",
events: {},
})
bot.transformers.desiredProperties.message.activity = true
bot.transformers.desiredProperties.message.application = true
bot.transformers.desiredProperties.message.applicationId = true
bot.transformers.desiredProperties.message.attachments = true
bot.transformers.desiredProperties.message.author = true
bot.transformers.desiredProperties.message.channelId = true
bot.transformers.desiredProperties.message.components = true
bot.transformers.desiredProperties.message.content = true
bot.transformers.desiredProperties.message.editedTimestamp = true
bot.transformers.desiredProperties.message.embeds = true
bot.transformers.desiredProperties.message.guildId = true
bot.transformers.desiredProperties.message.id = true
bot.transformers.desiredProperties.message.interaction.id = true
bot.transformers.desiredProperties.message.interaction.member = true
bot.transformers.desiredProperties.message.interaction.name = true
bot.transformers.desiredProperties.message.interaction.user = true
bot.transformers.desiredProperties.message.interaction.type = true
bot.transformers.desiredProperties.message.member = true
bot.transformers.desiredProperties.message.mentionedChannelIds = true
bot.transformers.desiredProperties.message.mentionedRoleIds = true
bot.transformers.desiredProperties.message.mentions = true
bot.transformers.desiredProperties.message.messageReference.messageId = true
bot.transformers.desiredProperties.message.messageReference.channelId = true
bot.transformers.desiredProperties.message.messageReference.guildId = true
bot.transformers.desiredProperties.message.nonce = true
bot.transformers.desiredProperties.message.reactions = true
bot.transformers.desiredProperties.message.stickerItems = true
bot.transformers.desiredProperties.message.thread = true
bot.transformers.desiredProperties.message.type = true
bot.transformers.desiredProperties.message.webhookId = true
const URL = 'https://discordeno.js.org/'
const IMAGE_HASH = '5fff867ae5f666fcd0626bd84f5e69c0'
const GUILD_ID = '785384884197392384'
const USER = {
accent_color: 0,
avatar: IMAGE_HASH,
banner: IMAGE_HASH,
bot: true,
discriminator: '1234',
email: 'discordeno@discordeno.com',
flags: UserFlags.BotHttpInteractions,
id: GUILD_ID,
locale: 'en',
mfa_enabled: true,
premium_type: PremiumTypes.Nitro,
public_flags: UserFlags.BotHttpInteractions,
system: true,
username: 'skillz',
verified: true,
}
const MEMBER = {
nick: 'John',
roles: ['111111111111111111', '222222222222222222', '333333333333333333'],
joined_at: '2022-01-01T00:00:00.000Z',
premium_since: '2022-02-01T00:00:00.000Z',
deaf: false,
mute: true,
pending: false,
permissions: '2147483647',
}
console.log('before the bench')
await memoryBenchmark(
'[transformer] message cache check',
() => ({
cache: [] as any[],
}), // function reutrn a new instance of object wanted to test with
(object, event: DiscordMessage) => object.cache.push(bot.transformers.message(bot, event)),
// function specify how to add event to the object/ run the object
[...new Array(MESSAGE_SIZE)].map(
(i) =>
({
activity: {
party_id: 'party_id',
type: MessageActivityTypes.Join,
},
application: {
bot_public: true,
bot_require_code_grant: true,
cover_image: IMAGE_HASH,
custom_install_url: 'https://google.com',
description: 'discordeno is the best lib ever',
flags: ApplicationFlags.GatewayGuildMembers,
guild_id: GUILD_ID,
icon: IMAGE_HASH,
id: GUILD_ID,
install_params: {
permissions: '8',
scopes: ['identify'],
},
name: 'skillz',
owner: USER,
primary_sku_id: GUILD_ID,
privacy_policy_url: 'https://discordeno.js.org',
role_connections_verification_url: 'https://discordeno.js.org',
rpc_origins: [],
slug: 'discordeno',
tags: ['discordeno', 'discordeno', 'discordeno', 'discordeno', 'discordeno'],
team: {
icon: IMAGE_HASH,
id: GUILD_ID,
members: [
{
membership_state: TeamMembershipStates.Accepted,
permissions: ['*'],
team_id: GUILD_ID,
user: USER,
},
{
membership_state: TeamMembershipStates.Accepted,
permissions: ['*'],
team_id: GUILD_ID,
user: USER,
},
],
name: 'discordeno',
owner_user_id: GUILD_ID,
},
terms_of_service_url: 'https://discordeno.js.org',
verify_key: IMAGE_HASH,
},
application_id: GUILD_ID,
attachments: [
{
content_type: 'application/json',
description: 'discordeno discordeno discordeno',
ephemeral: true,
filename: 'discordeno',
height: 100,
id: GUILD_ID,
proxy_url: 'https://discordeno.js.org',
size: 100,
url: 'https://discordeno.js.org',
width: 100,
},
{
content_type: 'application/json',
description: 'discordeno discordeno discordeno',
ephemeral: true,
filename: 'discordeno',
height: 100,
id: GUILD_ID,
proxy_url: 'https://discordeno.js.org',
size: 100,
url: 'https://discordeno.js.org',
width: 100,
},
],
author: USER,
channel_id: GUILD_ID,
components: [
{
type: 1,
components: [
{
custom_id: GUILD_ID,
disabled: true,
emoji: {
animated: true,
id: GUILD_ID,
name: 'discordeno',
},
label: 'discordeno',
style: ButtonStyles.Danger,
type: MessageComponentTypes.Button,
url: 'https://discordeno.js.org',
},
],
},
{
type: 1,
components: [
{
type: MessageComponentTypes.InputText,
custom_id: 'discordeno',
label: 'discordeno',
max_length: 100,
min_length: 100,
placeholder: 'discordeno',
required: true,
style: TextStyles.Paragraph,
value: 'discordeno',
},
],
},
{
type: 1,
components: [
{
type: MessageComponentTypes.SelectMenu,
custom_id: 'discordeno',
max_values: 100,
min_values: 100,
options: [
{
default: true,
description: 'idk idk idk',
emoji: {
animated: true,
id: GUILD_ID,
name: 'discordeno',
},
label: 'discordeno',
value: 'discordeno',
},
],
placeholder: 'discordeno',
},
],
},
],
content: 'discordeno',
edited_timestamp: new Date().toISOString(),
embeds: [
{
author: {
icon_url: URL,
name: 'discordeno',
proxy_icon_url: URL,
url: URL,
},
color: 0,
description: 'discordeno',
fields: [
{
name: 'discordeno',
value: 'discordeno',
inline: true,
},
{
name: 'discordeno',
value: 'discordeno',
inline: true,
},
],
footer: {
icon_url: URL,
proxy_icon_url: URL,
text: 'discordeno',
},
image: {
height: 100,
width: 100,
proxy_url: URL,
url: URL,
},
provider: {
name: 'discordeno',
url: URL,
},
thumbnail: {
height: 100,
width: 100,
proxy_url: URL,
url: URL,
},
timestamp: new Date().toISOString(),
title: 'discordeno',
type: 'rich',
url: URL,
video: {
height: 100,
width: 100,
proxy_url: URL,
url: URL,
},
},
],
flags: 64,
guild_id: GUILD_ID,
id: GUILD_ID,
interaction: {
id: GUILD_ID,
name: 'discordeno',
type: InteractionTypes.ApplicationCommand,
user: USER,
member: MEMBER,
},
member: MEMBER,
mention_channels: [
{
guild_id: GUILD_ID,
id: GUILD_ID,
name: 'discordeno',
type: 0,
},
],
mention_roles: ['111111111111111111', '222222222222222222'],
mention_everyone: false,
mentions: [USER, USER, USER],
message_reference: {
message_id: GUILD_ID,
channel_id: GUILD_ID,
guild_id: GUILD_ID,
fail_if_not_exists: true,
},
nonce: 'discordeno',
pinned: true,
position: 100,
reactions: [
{
count: 100,
emoji: {
animated: true,
id: GUILD_ID,
name: 'discordeno',
},
me: true,
},
],
sticker_items: [
{
format_type: StickerFormatTypes.APng,
id: GUILD_ID,
name: 'discordeno',
},
],
thread: {
id: '987654321098765432',
name: 'My Thread',
type: 11,
guild_id: '123456789012345678',
parent_id: '876543210987654321',
owner_id: '111111111111111111',
message_count: 10,
member_count: 5,
created_timestamp: 1651388000,
last_message_id: '876543210987654321',
applied_tags: ['discordeno'],
default_thread_rate_limit_per_user: 100,
member: {
flags: 100,
id: GUILD_ID,
join_timestamp: new Date().toISOString(),
user_id: GUILD_ID,
},
},
timestamp: new Date().toISOString(),
tts: true,
type: MessageTypes.Default,
webhook_id: GUILD_ID,
} as DiscordMessage),
), // array of event to test with
{ times: 1, log: false, table: false },
)
console.log('after the bench')
function oldtransformMessage(bot: Bot, payload: DiscordMessage): any {
const guildId = payload.guild_id ? bot.transformers.snowflake(payload.guild_id) : undefined
const userId = bot.transformers.snowflake(payload.author.id)
const message = {
// UNTRANSFORMED STUFF HERE
content: payload.content ?? '',
isFromBot: payload.author.bot ?? false,
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
tag: `${payload.author.username}#${payload.author.discriminator}`,
timestamp: Date.parse(payload.timestamp),
editedTimestamp: payload.edited_timestamp ? Date.parse(payload.edited_timestamp) : undefined,
bitfield: (payload.tts ? 1n : 0n) | (payload.mention_everyone ? 2n : 0n) | (payload.pinned ? 4n : 0n),
attachments: payload.attachments?.map((attachment) => bot.transformers.attachment(bot, attachment)),
embeds: payload.embeds?.map((embed) => bot.transformers.embed(bot, embed)),
reactions: payload.reactions?.map((reaction) => ({
me: reaction.me,
count: reaction.count,
emoji: bot.transformers.emoji(bot, reaction.emoji),
})),
type: payload.type,
activity: payload.activity
? {
type: payload.activity.type,
partyId: payload.activity.party_id,
}
: undefined,
application: payload.application,
flags: payload.flags,
interaction: payload.interaction
? {
id: bot.transformers.snowflake(payload.interaction.id),
type: payload.interaction.type,
name: payload.interaction.name,
user: bot.transformers.user(bot, payload.interaction.user),
member: payload.interaction.member
? {
id: userId,
guildId,
nick: payload.interaction.member.nick ?? undefined,
roles: payload.interaction.member.roles?.map((id) => bot.transformers.snowflake(id)),
joinedAt: payload.interaction.member.joined_at ? Date.parse(payload.interaction.member.joined_at) : undefined,
premiumSince: payload.interaction.member.premium_since ? Date.parse(payload.interaction.member.premium_since) : undefined,
toggles: new MemberToggles(payload.interaction.member),
avatar: payload.interaction.member.avatar ? iconHashToBigInt(payload.interaction.member.avatar) : undefined,
permissions: payload.interaction.member.permissions ? bot.transformers.snowflake(payload.interaction.member.permissions) : undefined,
communicationDisabledUntil: payload.interaction.member.communication_disabled_until
? Date.parse(payload.interaction.member.communication_disabled_until)
: undefined,
}
: undefined,
}
: undefined,
thread: payload.thread ? bot.transformers.channel(bot, { channel: payload.thread, guildId }) : undefined,
components: payload.components?.map((component) => bot.transformers.component(bot, component)),
stickerItems: payload.sticker_items?.map((sticker) => ({
id: bot.transformers.snowflake(sticker.id),
name: sticker.name,
formatType: sticker.format_type,
})),
// TRANSFORMED STUFF BELOW
id: bot.transformers.snowflake(payload.id),
guildId,
channelId: bot.transformers.snowflake(payload.channel_id),
webhookId: payload.webhook_id ? bot.transformers.snowflake(payload.webhook_id) : undefined,
authorId: userId,
applicationId: payload.application_id ? bot.transformers.snowflake(payload.application_id) : undefined,
messageReference: payload.message_reference
? {
messageId: payload.message_reference.message_id ? bot.transformers.snowflake(payload.message_reference.message_id) : undefined,
channelId: payload.message_reference.channel_id ? bot.transformers.snowflake(payload.message_reference.channel_id) : undefined,
guildId: payload.message_reference.guild_id ? bot.transformers.snowflake(payload.message_reference.guild_id) : undefined,
}
: undefined,
mentionedUserIds: payload.mentions ? payload.mentions.map((m) => bot.transformers.snowflake(m.id)) : [],
mentionedRoleIds: payload.mention_roles ? payload.mention_roles.map((id) => bot.transformers.snowflake(id)) : [],
mentionedChannelIds: [
// Keep any ids tht discord sends
...(payload.mention_channels ?? []).map((m) => bot.transformers.snowflake(m.id)),
// Add any other ids that can be validated in a channel mention format
...(payload.content?.match(CHANNEL_MENTION_REGEX) ?? []).map((text) =>
// converts the <#123> into 123
bot.transformers.snowflake(text.substring(2, text.length - 1)),
),
],
member: payload.member && guildId ? bot.transformers.member(bot, payload.member, guildId, userId) : undefined,
nonce: payload.nonce,
}
return message
}
await memoryBenchmark(
'[transformer] old message cache check',
() => ({
cache: [] as any[],
}), // function reutrn a new instance of object wanted to test with
(object, event: DiscordMessage) => object.cache.push(oldtransformMessage(bot as any, event)),
// function specify how to add event to the object/ run the object
[...new Array(MESSAGE_SIZE)].map(
(i) =>
({
activity: {
party_id: 'party_id',
type: MessageActivityTypes.Join,
},
application: {
bot_public: true,
bot_require_code_grant: true,
cover_image: IMAGE_HASH,
custom_install_url: 'https://google.com',
description: 'discordeno is the best lib ever',
flags: ApplicationFlags.GatewayGuildMembers,
guild_id: GUILD_ID,
icon: IMAGE_HASH,
id: GUILD_ID,
install_params: {
permissions: '8',
scopes: ['identify'],
},
name: 'skillz',
owner: USER,
primary_sku_id: GUILD_ID,
privacy_policy_url: 'https://discordeno.js.org',
role_connections_verification_url: 'https://discordeno.js.org',
rpc_origins: [],
slug: 'discordeno',
tags: ['discordeno', 'discordeno', 'discordeno', 'discordeno', 'discordeno'],
team: {
icon: IMAGE_HASH,
id: GUILD_ID,
members: [
{
membership_state: TeamMembershipStates.Accepted,
permissions: ['*'],
team_id: GUILD_ID,
user: USER,
},
{
membership_state: TeamMembershipStates.Accepted,
permissions: ['*'],
team_id: GUILD_ID,
user: USER,
},
],
name: 'discordeno',
owner_user_id: GUILD_ID,
},
terms_of_service_url: 'https://discordeno.js.org',
verify_key: IMAGE_HASH,
},
application_id: GUILD_ID,
attachments: [
{
content_type: 'application/json',
description: 'discordeno discordeno discordeno',
ephemeral: true,
filename: 'discordeno',
height: 100,
id: GUILD_ID,
proxy_url: 'https://discordeno.js.org',
size: 100,
url: 'https://discordeno.js.org',
width: 100,
},
{
content_type: 'application/json',
description: 'discordeno discordeno discordeno',
ephemeral: true,
filename: 'discordeno',
height: 100,
id: GUILD_ID,
proxy_url: 'https://discordeno.js.org',
size: 100,
url: 'https://discordeno.js.org',
width: 100,
},
],
author: USER,
channel_id: GUILD_ID,
components: [
{
type: 1,
components: [
{
custom_id: GUILD_ID,
disabled: true,
emoji: {
animated: true,
id: GUILD_ID,
name: 'discordeno',
},
label: 'discordeno',
style: ButtonStyles.Danger,
type: MessageComponentTypes.Button,
url: 'https://discordeno.js.org',
},
],
},
{
type: 1,
components: [
{
type: MessageComponentTypes.InputText,
custom_id: 'discordeno',
label: 'discordeno',
max_length: 100,
min_length: 100,
placeholder: 'discordeno',
required: true,
style: TextStyles.Paragraph,
value: 'discordeno',
},
],
},
{
type: 1,
components: [
{
type: MessageComponentTypes.SelectMenu,
custom_id: 'discordeno',
max_values: 100,
min_values: 100,
options: [
{
default: true,
description: 'idk idk idk',
emoji: {
animated: true,
id: GUILD_ID,
name: 'discordeno',
},
label: 'discordeno',
value: 'discordeno',
},
],
placeholder: 'discordeno',
},
],
},
],
content: 'discordeno',
edited_timestamp: new Date().toISOString(),
embeds: [
{
author: {
icon_url: URL,
name: 'discordeno',
proxy_icon_url: URL,
url: URL,
},
color: 0,
description: 'discordeno',
fields: [
{
name: 'discordeno',
value: 'discordeno',
inline: true,
},
{
name: 'discordeno',
value: 'discordeno',
inline: true,
},
],
footer: {
icon_url: URL,
proxy_icon_url: URL,
text: 'discordeno',
},
image: {
height: 100,
width: 100,
proxy_url: URL,
url: URL,
},
provider: {
name: 'discordeno',
url: URL,
},
thumbnail: {
height: 100,
width: 100,
proxy_url: URL,
url: URL,
},
timestamp: new Date().toISOString(),
title: 'discordeno',
type: 'rich',
url: URL,
video: {
height: 100,
width: 100,
proxy_url: URL,
url: URL,
},
},
],
flags: 64,
guild_id: GUILD_ID,
id: GUILD_ID,
interaction: {
id: GUILD_ID,
name: 'discordeno',
type: InteractionTypes.ApplicationCommand,
user: USER,
member: MEMBER,
},
member: MEMBER,
mention_channels: [
{
guild_id: GUILD_ID,
id: GUILD_ID,
name: 'discordeno',
type: 0,
},
],
mention_roles: ['111111111111111111', '222222222222222222'],
mention_everyone: false,
mentions: [USER, USER, USER],
message_reference: {
message_id: GUILD_ID,
channel_id: GUILD_ID,
guild_id: GUILD_ID,
fail_if_not_exists: true,
},
nonce: 'discordeno',
pinned: true,
position: 100,
reactions: [
{
count: 100,
emoji: {
animated: true,
id: GUILD_ID,
name: 'discordeno',
},
me: true,
},
],
sticker_items: [
{
format_type: StickerFormatTypes.APng,
id: GUILD_ID,
name: 'discordeno',
},
],
thread: {
id: '987654321098765432',
name: 'My Thread',
type: 11,
guild_id: '123456789012345678',
parent_id: '876543210987654321',
owner_id: '111111111111111111',
message_count: 10,
member_count: 5,
created_timestamp: 1651388000,
last_message_id: '876543210987654321',
applied_tags: ['discordeno'],
default_thread_rate_limit_per_user: 100,
member: {
flags: 100,
id: GUILD_ID,
join_timestamp: new Date().toISOString(),
user_id: GUILD_ID,
},
},
timestamp: new Date().toISOString(),
tts: true,
type: MessageTypes.Default,
webhook_id: GUILD_ID,
} as DiscordMessage),
), // array of event to test with
{ times: 1, log: false, table: false },
)
@@ -35,9 +35,13 @@ export async function memoryBenchmark<O, E>(
// Set the memory stats for when files are loaded in.
results.loaded = process.memoryUsage()
events.forEach((event) => {
// events.forEach((event, i) => {
// console.log('logging event', i)
// objectFeeder(object, event)
// })
for (const event of events) {
objectFeeder(object, event)
})
}
if (options.log) {
console.log(`[INFO] Processed ${events.length} events.`)
+449 -5
View File
@@ -61,11 +61,6 @@ import { transformEmbed, type Embed } from './transformers/embed.js'
import { transformEmoji, type Emoji } from './transformers/emoji.js'
import { transformGatewayBot, type GetGatewayBot } from './transformers/gatewayBot.js'
import { transformGuild, type Guild } from './transformers/guild.js'
import { transformIntegration, type Integration } from './transformers/integration.js'
import { transformInteraction, transformInteractionDataOption, type Interaction, type InteractionDataOption } from './transformers/interaction.js'
import { transformInvite, type Invite } from './transformers/invite.js'
import { transformMember, transformUser, type Member, type User } from './transformers/member.js'
import { transformMessage, type Message } from './transformers/message.js'
import {
transformActivityToDiscordActivity,
transformApplicationCommandOptionChoiceToDiscordApplicationCommandOptionChoice,
@@ -79,6 +74,11 @@ import {
transformTeamToDiscordTeam,
transformUserToDiscordUser,
} from './transformers/index.js'
import { transformIntegration, type Integration } from './transformers/integration.js'
import { transformInteraction, transformInteractionDataOption, type Interaction, type InteractionDataOption } from './transformers/interaction.js'
import { transformInvite, type Invite } from './transformers/invite.js'
import { transformMember, transformUser, type Member, type User } from './transformers/member.js'
import { transformMessage, type Message } from './transformers/message.js'
import { transformPresence, type PresenceUpdate } from './transformers/presence.js'
import { transformAllowedMentionsToDiscordAllowedMentions } from './transformers/reverse/allowedMentions.js'
import { transformCreateApplicationCommandToDiscordCreateApplicationCommand } from './transformers/reverse/createApplicationCommand.js'
@@ -99,6 +99,227 @@ import { transformWidgetSettings, type GuildWidgetSettings } from './transformer
import type { BotInteractionResponse, DiscordComponent, DiscordInteractionResponse } from './typings.js'
export interface Transformers {
customizers: {
message: (bot: Bot, payload: DiscordMessage, message: Message) => any
}
desiredProperties: {
attachment: {
id: boolean
filename: boolean
contentType: boolean
size: boolean
url: boolean
proxyUrl: boolean
height: boolean
width: boolean
ephemeral: boolean
description: boolean
}
channel: {
type: boolean
position: boolean
name: boolean
topic: boolean
nsfw: boolean
bitrate: boolean
userLimit: boolean
rateLimitPerUser: boolean
rtcRegion: boolean
videoQualityMode: boolean
guildId: boolean
lastPinTimestamp: boolean
permissionOverwrites: boolean
id: boolean
permissions: boolean
lastMessageId: boolean
ownerId: boolean
applicationId: boolean
managed: boolean
parentId: boolean
memberCount: boolean
messageCount: boolean
archiveTimestamp: boolean
autoArchiveDuration: boolean
botIsMember: boolean
archived: boolean
locked: boolean
invitable: boolean
createTimestamp: boolean
newlyCreated: boolean
flags: boolean
}
emoji: {
id: boolean
name: boolean
roles: boolean
user: boolean
}
guild: {
afkTimeout: boolean
approximateMemberCount: boolean
approximatePresenceCount: boolean
defaultMessageNotifications: boolean
description: boolean
explicitContentFilter: boolean
maxMembers: boolean
maxPresences: boolean
maxVideoChannelUsers: boolean
mfaLevel: boolean
name: boolean
nsfwLevel: boolean
preferredLocale: boolean
premiumSubscriptionCount: boolean
premiumTier: boolean
stageInstances: boolean
systemChannelFlags: boolean
vanityUrlCode: boolean
verificationLevel: boolean
welcomeScreen: boolean
discoverySplash: boolean
joinedAt: boolean
memberCount: boolean
shardId: boolean
icon: boolean
banner: boolean
splash: boolean
id: boolean
ownerId: boolean
permissions: boolean
afkChannelId: boolean
widgetChannelId: boolean
applicationId: boolean
systemChannelId: boolean
rulesChannelId: boolean
publicUpdatesChannelId: boolean
premiumProgressBarEnabled: boolean
}
invite: {
channelId: boolean
code: boolean
createdAt: boolean
guildId: boolean
inviter: boolean
maxAge: boolean
maxUses: boolean
targetType: boolean
targetUser: boolean
targetApplication: boolean
temporary: boolean
uses: boolean
}
member: {
id: boolean
guildId: boolean
user: boolean
nick: boolean
roles: boolean
joinedAt: boolean
premiumSince: boolean
avatar: boolean
permissions: boolean
communicationDisabledUntil: boolean
}
message: {
activity: boolean
application: boolean
applicationId: boolean
attachments: boolean
author: boolean
channelId: boolean
components: boolean
content: boolean
editedTimestamp: boolean
embeds: boolean
guildId: boolean
id: boolean
interaction: {
id: boolean
member: boolean
name: boolean
user: boolean
type: boolean
}
member: boolean
mentionedChannelIds: boolean
mentionedRoleIds: boolean
mentions: boolean
messageReference: {
messageId: boolean
channelId: boolean
guildId: boolean
}
nonce: boolean
reactions: boolean
stickerItems: boolean
thread: boolean
type: boolean
webhookId: boolean
}
role: {
name: boolean;
guildId: boolean;
position: boolean;
color: boolean;
id: boolean;
botId: boolean;
integrationId: boolean;
permissions: boolean;
icon: boolean;
unicodeEmoji: boolean;
}
scheduledEvent: {
id: boolean;
guildId: boolean;
channelId: boolean
creatorId: boolean
scheduledStartTime: boolean
scheduledEndTime: boolean
entityId: boolean
creator: boolean
name: boolean
description: boolean
privacyLevel: boolean
status: boolean
entityType: boolean
userCount: boolean
location: boolean
image: boolean
}
stageInstance: {
id: boolean
guildId: boolean
channelId: boolean
topic: boolean
guildScheduledEventId: boolean
}
sticker: {
id: boolean
packId: boolean
name: boolean
description: boolean
tags: boolean
type: boolean
formatType: boolean
available: boolean
guildId: boolean
user: boolean
sortValue: boolean
}
webhook: {
id: boolean;
type: boolean
guildId: boolean
channelId: boolean
user: boolean
name: boolean
avatar: boolean
token: boolean
applicationId: boolean
sourceGuild: boolean
sourceChannel: boolean
url: boolean
}
}
reverse: {
allowedMentions: (bot: Bot, payload: AllowedMentions) => DiscordAllowedMentions
embed: (bot: Bot, payload: Embed) => DiscordEmbed
@@ -159,6 +380,229 @@ export interface Transformers {
export function createTransformers(options: Partial<Transformers>): Transformers {
return {
customizers: {
message(bot, payload, message) {
return message
},
},
desiredProperties: {
attachment: {
id: false,
filename: false,
contentType: false,
size: false,
url: false,
proxyUrl: false,
height: false,
width: false,
ephemeral: false,
description: false,
},
channel: {
type: false,
position: false,
name: false,
topic: false,
nsfw: false,
bitrate: false,
userLimit: false,
rateLimitPerUser: false,
rtcRegion: false,
videoQualityMode: false,
guildId: false,
lastPinTimestamp: false,
permissionOverwrites: false,
id: false,
permissions: false,
lastMessageId: false,
ownerId: false,
applicationId: false,
managed: false,
parentId: false,
memberCount: false,
messageCount: false,
archiveTimestamp: false,
autoArchiveDuration: false,
botIsMember: false,
archived: false,
locked: false,
invitable: false,
createTimestamp: false,
newlyCreated: false,
flags: false,
},
emoji: {
id: false,
name: false,
roles: false,
user: false,
},
guild: {
afkTimeout: false,
approximateMemberCount: false,
approximatePresenceCount: false,
defaultMessageNotifications: false,
description: false,
explicitContentFilter: false,
maxMembers: false,
maxPresences: false,
maxVideoChannelUsers: false,
mfaLevel: false,
name: false,
nsfwLevel: false,
preferredLocale: false,
premiumSubscriptionCount: false,
premiumTier: false,
stageInstances: false,
systemChannelFlags: false,
vanityUrlCode: false,
verificationLevel: false,
welcomeScreen: false,
discoverySplash: false,
joinedAt: false,
memberCount: false,
shardId: false,
icon: false,
banner: false,
splash: false,
id: false,
ownerId: false,
permissions: false,
afkChannelId: false,
widgetChannelId: false,
applicationId: false,
systemChannelId: false,
rulesChannelId: false,
publicUpdatesChannelId: false,
premiumProgressBarEnabled: false,
},
invite: {
channelId: false,
code: false,
createdAt: false,
guildId: false,
inviter: false,
maxAge: false,
maxUses: false,
targetType: false,
targetUser: false,
targetApplication: false,
temporary: false,
uses: false,
},
member: {
id: false,
guildId: false,
user: false,
nick: false,
roles: false,
joinedAt: false,
premiumSince: false,
avatar: false,
permissions: false,
communicationDisabledUntil: false,
},
message: {
activity: false,
application: false,
applicationId: false,
attachments: false,
author: false,
channelId: false,
components: false,
content: false,
editedTimestamp: false,
embeds: false,
guildId: false,
id: false,
interaction: {
id: false,
member: false,
name: false,
type: false,
user: false,
},
member: false,
mentionedChannelIds: false,
mentionedRoleIds: false,
mentions: false,
messageReference: {
messageId: false,
channelId: false,
guildId: false,
},
nonce: false,
reactions: false,
stickerItems: false,
thread: false,
type: false,
webhookId: false,
},
role: {
name: false,
guildId: false,
position: false,
color: false,
id: false,
botId: false,
integrationId: false,
permissions: false,
icon: false,
unicodeEmoji: false,
},
scheduledEvent: {
id: false,
guildId: false,
channelId: false,
creatorId: false,
scheduledStartTime: false,
scheduledEndTime: false,
entityId: false,
creator: false,
name: false,
description: false,
privacyLevel: false,
status: false,
entityType: false,
userCount: false,
location: false,
image: false,
},
stageInstance: {
id: false,
guildId: false,
channelId: false,
topic: false,
guildScheduledEventId: false,
},
sticker: {
id: false,
packId: false,
name: false,
description: false,
tags: false,
type: false,
formatType: false,
available: false,
guildId: false,
user: false,
sortValue: false,
},
webhook: {
id: false,
type: false,
guildId: false,
channelId: false,
user: false,
name: false,
avatar: false,
token: false,
applicationId: false,
sourceGuild: false,
sourceChannel: false,
url: false,
}
},
reverse: {
allowedMentions: options.reverse?.allowedMentions ?? transformAllowedMentionsToDiscordAllowedMentions,
embed: options.reverse?.embed ?? transformEmbedToDiscordEmbed,
+344 -84
View File
@@ -1,87 +1,307 @@
import type { DiscordMessage } from '@discordeno/types'
import type { DiscordMessage, InteractionTypes, MessageActivityTypes, MessageTypes, StickerFormatTypes } from '@discordeno/types'
import { CHANNEL_MENTION_REGEX } from '../constants.js'
import { iconHashToBigInt, type Bot } from '../index.js'
import type { Optionalize } from '../optionalize.js'
import { MemberToggles } from './toggles/member.js'
import { snowflakeToTimestamp, type Bot } from '../index.js'
import { MessageFlags } from '../typings.js'
import type { Attachment } from './attachment.js'
import type { Channel } from './channel.js'
import type { Component } from './component.js'
import type { Embed } from './embed.js'
import type { Emoji } from './emoji.js'
import type { Member, User } from './member.js'
import { ToggleBitfield } from './toggles/ToggleBitfield.js'
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function transformMessage(bot: Bot, payload: DiscordMessage) {
const baseMessage: Partial<Message> & MessageBase = {
get crossposted() {
return this.flags?.contains(MessageFlags.Crossposted) ?? false
},
set crossposted(value: boolean) {
if (!this.flags) return
if (!this.flags) return
if (value) this.flags.add(MessageFlags.Crossposted)
else this.flags.remove(MessageFlags.Crossposted)
},
get ephemeral() {
return this.flags?.contains(MessageFlags.Ephemeral) ?? false
},
set ephemeral(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.Ephemeral)
else this.flags.remove(MessageFlags.Ephemeral)
},
get failedToMentionSomeRolesInThread() {
return this.flags?.contains(MessageFlags.FailedToMentionSomeRolesInThread) ?? false
},
set failedToMentionSomeRolesInThread(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.FailedToMentionSomeRolesInThread)
else this.flags.remove(MessageFlags.FailedToMentionSomeRolesInThread)
},
get hasThread() {
return this.flags?.contains(MessageFlags.HasThread) ?? false
},
set hasThread(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.HasThread)
else this.flags.remove(MessageFlags.HasThread)
},
get isCrosspost() {
return this.flags?.contains(MessageFlags.IsCrosspost) ?? false
},
set isCrosspost(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.IsCrosspost)
else this.flags.remove(MessageFlags.IsCrosspost)
},
get loading() {
return this.flags?.contains(MessageFlags.Loading) ?? false
},
set loading(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.Loading)
else this.flags.remove(MessageFlags.Loading)
},
get mentionedUserIds() {
return this.mentions?.map((user) => user.id) ?? []
},
get mentionEveryone() {
return this.bitfield?.contains(2) ?? false
},
set mentionEveryone(value: boolean) {
if (!this.bitfield) return
if (value) this.bitfield.add(2)
else this.bitfield.remove(2)
},
get pinned() {
return this.bitfield?.contains(3) ?? false
},
set pinned(value: boolean) {
if (!this.bitfield) return
if (value) this.bitfield.add(3)
else this.bitfield.remove(3)
},
get sourceMessageDeleted() {
return this.flags?.contains(MessageFlags.SourceMessageDeleted) ?? false
},
set sourceMessageDeleted(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.SourceMessageDeleted)
else this.flags.remove(MessageFlags.SourceMessageDeleted)
},
get suppressEmbeds() {
return this.flags?.contains(MessageFlags.SuppressEmbeds) ?? false
},
set suppressEmbeds(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.SuppressEmbeds)
else this.flags.remove(MessageFlags.SuppressEmbeds)
},
get suppressNotifications() {
return this.flags?.contains(MessageFlags.SuppressNotifications) ?? false
},
set suppressNotifications(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.SuppressNotifications)
else this.flags.remove(MessageFlags.SuppressNotifications)
},
get timestamp() {
return this.id ? snowflakeToTimestamp(this.id) : 0
},
get tts() {
return this.bitfield?.contains(1) ?? false
},
set tts(value: boolean) {
if (!this.bitfield) return
if (value) this.bitfield.add(1)
else this.bitfield.remove(1)
},
get urgent() {
return this.flags?.contains(MessageFlags.Urgent) ?? false
},
set urgent(value: boolean) {
if (!this.flags) return
if (value) this.flags.add(MessageFlags.Urgent)
else this.flags.remove(MessageFlags.Urgent)
},
}
export interface MessageBase {
/** Holds all the boolean values on this message. */
bitfield?: ToggleBitfield
/** Whether this message has been published to subscribed channels (via Channel Following) */
crossposted: boolean
/** Whether this message is only visible to the user who invoked the Interaction */
ephemeral: boolean
/** Whether this message failed to mention some roles and add their members to the thread */
failedToMentionSomeRolesInThread: boolean
/** Message flags combined as a bitfield */
flags?: ToggleBitfield
/** Whether this message has an associated thread, with the same id as the message */
hasThread: boolean
/** Whether this message originated from a message in another channel (via Channel Following) */
isCrosspost: boolean
/** Whether this message is an Interaction Response and the bot is "thinking" */
loading: boolean
/** The ids of the users who were mentioned in this message. */
mentionedUserIds: bigint[]
/** Whether this message mentions everyone */
mentionEveryone: boolean
/** Whether this message is pinned */
pinned: boolean
/** Whether the source message for this crosspost has been deleted (via Channel Following) */
sourceMessageDeleted: boolean
/** Whether do not include any embeds when serializing this message */
suppressEmbeds: boolean
/** Whether this message will not trigger push and desktop notifications */
suppressNotifications: boolean
/** The timestamp in milliseconds when this message was created */
timestamp: number
/** Whether this was a TTS message. */
tts: boolean
/** Whether this message came from the urgent message system */
urgent: boolean
}
export interface Message extends MessageBase {
/** Sent with Rich Presence-related chat embeds */
activity?: {
/** Type of message activity */
type: MessageActivityTypes
/** party_id from a Rich Presence event */
partyId?: string
}
/** if the message is an Interaction or application-owned webhook, this is the id of the application */
applicationId?: bigint
/** Any attached files on this message. */
attachments?: Attachment[]
/** The author of this message (not guaranteed to be a valid user) Note: The author object follows the structure of the user object, but is only a valid user in the case where the message is generated by a user or bot user. If the message is generated by a webhook, the author object corresponds to the webhook's id, username, and avatar. You can tell if a message is generated by a webhook by checking for the webhook_id on the message object. */
author: User
/** id of the channel the message was sent in */
channelId: bigint
/** The components related to this message */
components: Component[]
/** Contents of the message */
content: string
/** The timestamp in milliseconds when this message was edited last. */
editedTimestamp?: number
/** Any embedded content */
embeds?: Embed[]
/** id of the guild the message was sent in Note: For MESSAGE_CREATE and MESSAGE_UPDATE events, the message object may not contain a guild_id or member field since the events are sent directly to the receiving user and the bot who sent the message, rather than being sent through the guild like non-ephemeral messages. */
guildId?: bigint
/** id of the message */
id: bigint
/** Sent if the message is a response to an Interaction */
interaction?: {
/** Id of the interaction */
id: bigint
/** The member who invoked the interaction in the guild */
member?: Member
/** The name of the ApplicationCommand including the name of the subcommand/subcommand group */
name: string
/** The type of interaction */
type: InteractionTypes
/** The user who invoked the interaction */
user: User
}
/** Member properties for this message's author Note: The member object exists in MESSAGE_CREATE and MESSAGE_UPDATE events from text-based guild channels. This allows bots to obtain real-time member data without requiring bots to store member state in memory. */
member?: Member
/** Users specifically mentioned in the message Note: The user objects in the mentions array will only have the partial member field present in MESSAGE_CREATE and MESSAGE_UPDATE events from text-based guild channels. */
mentions?: User[]
/** Channels specifically mentioned in this message Note: Not all channel mentions in a message will appear in mention_channels. Only textual channels that are visible to everyone in a lurkable guild will ever be included. Only crossposted messages (via Channel Following) currently include mention_channels at all. If no mentions in the message meet these requirements, this field will not be sent. */
mentionedChannelIds?: bigint[]
/** Roles specifically mentioned in this message */
mentionedRoleIds?: bigint[]
/** Data showing the source of a crossposted channel follow add, pin or reply message */
messageReference?: {
/** id of the originating message's channel Note: channel_id is optional when creating a reply, but will always be present when receiving an event/response that includes this data model. */
channelId?: bigint
/** id of the originating message's guild */
guildId?: bigint
/** id of the originating message */
messageId?: bigint
}
/** Used for validating a message was sent */
nonce?: string | number
/** Reactions on this message. */
reactions?: Array<{
/** Whether the current user reacted using this emoji */
me: boolean
/** Times this emoji has been used to react */
count: number
/** Emoji information */
emoji: Emoji
}>
/** Sent if the message contains stickers */
stickerItems?: Array<{
/** The id of this sticker. */
id: bigint
/** The name of this sticker. */
name: string
/** The type of this stickers format. */
formatType: StickerFormatTypes
}>
/** Type of message */
type: MessageTypes
/** The thread that was started from this message, includes thread member object */
thread?: Channel
/** If the message is generated by a webhook, this is the webhook's id */
webhookId?: bigint
}
const EMPTY_STRING = ''
export function transformMessage(bot: Bot, payload: DiscordMessage): Message {
const guildId = payload.guild_id ? bot.transformers.snowflake(payload.guild_id) : undefined
const userId = bot.transformers.snowflake(payload.author.id)
const message = {
// UNTRANSFORMED STUFF HERE
content: payload.content ?? '',
isFromBot: payload.author.bot ?? false,
tag: `${payload.author.username}#${payload.author.discriminator}`,
timestamp: Date.parse(payload.timestamp),
editedTimestamp: payload.edited_timestamp ? Date.parse(payload.edited_timestamp) : undefined,
bitfield: (payload.tts ? 1n : 0n) | (payload.mention_everyone ? 2n : 0n) | (payload.pinned ? 4n : 0n),
attachments: payload.attachments?.map((attachment) => bot.transformers.attachment(bot, attachment)),
embeds: payload.embeds?.map((embed) => bot.transformers.embed(bot, embed)),
reactions: payload.reactions?.map((reaction) => ({
me: reaction.me,
count: reaction.count,
emoji: bot.transformers.emoji(bot, reaction.emoji),
})),
type: payload.type,
activity: payload.activity
? {
type: payload.activity.type,
partyId: payload.activity.party_id,
}
: undefined,
application: payload.application,
flags: payload.flags,
interaction: payload.interaction
? {
id: bot.transformers.snowflake(payload.interaction.id),
type: payload.interaction.type,
name: payload.interaction.name,
user: bot.transformers.user(bot, payload.interaction.user),
member: payload.interaction.member
? {
id: userId,
guildId,
nick: payload.interaction.member.nick ?? undefined,
roles: payload.interaction.member.roles?.map((id) => bot.transformers.snowflake(id)),
joinedAt: payload.interaction.member.joined_at ? Date.parse(payload.interaction.member.joined_at) : undefined,
premiumSince: payload.interaction.member.premium_since ? Date.parse(payload.interaction.member.premium_since) : undefined,
toggles: new MemberToggles(payload.interaction.member),
avatar: payload.interaction.member.avatar ? iconHashToBigInt(payload.interaction.member.avatar) : undefined,
permissions: payload.interaction.member.permissions ? bot.transformers.snowflake(payload.interaction.member.permissions) : undefined,
communicationDisabledUntil: payload.interaction.member.communication_disabled_until
? Date.parse(payload.interaction.member.communication_disabled_until)
: undefined,
}
: undefined,
}
: undefined,
thread: payload.thread ? bot.transformers.channel(bot, { channel: payload.thread, guildId }) : undefined,
components: payload.components?.map((component) => bot.transformers.component(bot, component)),
stickerItems: payload.sticker_items?.map((sticker) => ({
id: bot.transformers.snowflake(sticker.id),
name: sticker.name,
formatType: sticker.format_type,
})),
const message: Message = Object.create(baseMessage)
message.bitfield = new ToggleBitfield()
message.flags = new ToggleBitfield(payload.flags)
// TRANSFORMED STUFF BELOW
id: bot.transformers.snowflake(payload.id),
guildId,
channelId: bot.transformers.snowflake(payload.channel_id),
webhookId: payload.webhook_id ? bot.transformers.snowflake(payload.webhook_id) : undefined,
authorId: userId,
applicationId: payload.application_id ? bot.transformers.snowflake(payload.application_id) : undefined,
messageReference: payload.message_reference
? {
messageId: payload.message_reference.message_id ? bot.transformers.snowflake(payload.message_reference.message_id) : undefined,
channelId: payload.message_reference.channel_id ? bot.transformers.snowflake(payload.message_reference.channel_id) : undefined,
guildId: payload.message_reference.guild_id ? bot.transformers.snowflake(payload.message_reference.guild_id) : undefined,
}
: undefined,
mentionedUserIds: payload.mentions ? payload.mentions.map((m) => bot.transformers.snowflake(m.id)) : [],
mentionedRoleIds: payload.mention_roles ? payload.mention_roles.map((id) => bot.transformers.snowflake(id)) : [],
mentionedChannelIds: [
const props = bot.transformers.desiredProperties.message
if (props.author && props.author) message.author = bot.transformers.user(bot, payload.author)
if (payload.application_id && props.applicationId) message.applicationId = bot.transformers.snowflake(payload.application_id)
if (payload.attachments?.length && props.attachments) {
message.attachments = payload.attachments.map((attachment) => bot.transformers.attachment(bot, attachment))
}
if (props.channelId && props.channelId) message.channelId = bot.transformers.snowflake(payload.channel_id)
if (props.components && payload.components?.length) message.components = payload.components.map((comp) => bot.transformers.component(bot, comp))
if (props.content && props.content) message.content = payload.content ?? EMPTY_STRING
if (payload.edited_timestamp && props.editedTimestamp) message.editedTimestamp = Date.parse(payload.edited_timestamp)
if (payload.embeds?.length && props.embeds) message.embeds = payload.embeds.map((embed) => bot.transformers.embed(bot, embed))
if (guildId && props.guildId) message.guildId = guildId
if (props.id && payload.id) message.id = bot.transformers.snowflake(payload.id)
if (payload.interaction) {
const interaction = {} as NonNullable<Message['interaction']>
let edited = false
if (props.interaction.id) {
interaction.id = bot.transformers.snowflake(payload.interaction.id)
edited = true
}
if (props.interaction.member && payload.interaction.member) {
// @ts-expect-error TODO: partial - check why this is partial and handle as needed
interaction.member = bot.transformers.member(bot, payload.interaction.member, guildId, payload.interaction.user.id)
edited = true
}
if (props.interaction.name) {
interaction.name = payload.interaction.name
edited = true
}
if (props.interaction.type) {
interaction.type = payload.interaction.type
edited = true
}
if (props.interaction.user) {
interaction.user = bot.transformers.user(bot, payload.interaction.user)
edited = true
}
if (edited) message.interaction = interaction
}
if (props.member && payload.member && guildId) message.member = bot.transformers.member(bot, payload.member, guildId, userId)
if (payload.mention_everyone) message.mentionEveryone = true
if (props.mentionedChannelIds && payload.mention_channels?.length) {
message.mentionedChannelIds = [
// Keep any ids tht discord sends
...(payload.mention_channels ?? []).map((m) => bot.transformers.snowflake(m.id)),
// Add any other ids that can be validated in a channel mention format
@@ -89,12 +309,52 @@ export function transformMessage(bot: Bot, payload: DiscordMessage) {
// converts the <#123> into 123
bot.transformers.snowflake(text.substring(2, text.length - 1)),
),
],
member: payload.member && guildId ? bot.transformers.member(bot, payload.member, guildId, userId) : undefined,
nonce: payload.nonce,
]
}
if (props.mentionedRoleIds && payload.mention_roles?.length) {
message.mentionedRoleIds = payload.mention_roles.map((id) => bot.transformers.snowflake(id))
}
if (props.mentions && payload.mentions?.length) {
message.mentions = payload.mentions.map((user) => bot.transformers.user(bot, user))
}
if (payload.message_reference) {
const reference = {} as NonNullable<Message['messageReference']>
let edited = false
return message as Optionalize<typeof message>
if (props.messageReference.channelId && payload.message_reference.channel_id) {
reference.channelId = bot.transformers.snowflake(payload.message_reference.channel_id)
edited = true
}
if (props.messageReference.guildId && payload.message_reference.guild_id) {
reference.guildId = bot.transformers.snowflake(payload.message_reference.guild_id)
edited = true
}
if (props.messageReference.messageId && payload.message_reference.message_id) {
reference.messageId = bot.transformers.snowflake(payload.message_reference.message_id)
edited = true
}
if (edited) message.messageReference = reference
}
if (payload.nonce && props.nonce) message.nonce = payload.nonce
if (payload.pinned) message.pinned = true
if (payload.reactions?.length && props.reactions) {
message.reactions = payload.reactions.map((reaction) => ({
me: reaction.me,
count: reaction.count,
emoji: bot.transformers.emoji(bot, reaction.emoji),
}))
}
if (props.stickerItems && payload.sticker_items?.length)
message.stickerItems = payload.sticker_items.map((item) => ({
id: bot.transformers.snowflake(item.id),
name: item.name,
formatType: item.format_type,
}))
if (payload.tts) message.tts = true
if (props.thread && payload.thread) message.thread = bot.transformers.channel(bot, { channel: payload.thread, guildId })
if (props.type && props.type) message.type = payload.type
if (payload.webhook_id && props.webhookId) message.webhookId = bot.transformers.snowflake(payload.webhook_id)
return bot.transformers.customizers.message(bot, payload, message)
}
export interface Message extends ReturnType<typeof transformMessage> {}
@@ -21,6 +21,10 @@ export class ToggleBitfield {
this.bitfield &= ~bits
return this
}
toJSON(): number {
return this.bitfield;
}
}
export class ToggleBitfieldBigint {
+23
View File
@@ -202,3 +202,26 @@ export interface BotGatewayHandlerOptions {
INTEGRATION_UPDATE: typeof handlers.handleIntegrationUpdate
INTEGRATION_DELETE: typeof handlers.handleIntegrationDelete
}
export enum MessageFlags {
/** Whether this message has been published to subscribed channels (via Channel Following) */
Crossposted = 1 << 0,
/** Whether this message originated from a message in another channel (via Channel Following) */
IsCrosspost = 1 << 1,
/** Whether do not include any embeds when serializing this message */
SuppressEmbeds = 1 << 2,
/** Whether the source message for this crosspost has been deleted (via Channel Following) */
SourceMessageDeleted = 1 << 3,
/** Whether this message came from the urgent message system */
Urgent = 1 << 4,
/** Whether this message has an associated thread, with the same id as the message */
HasThread = 1 << 5,
/** Whether this message is only visible to the user who invoked the Interaction */
Ephemeral = 1 << 6,
/** Whether this message is an Interaction Response and the bot is "thinking" */
Loading = 1 << 7,
/** Whether this message failed to mention some roles and add their members to the thread */
FailedToMentionSomeRolesInThread = 1 << 8,
/** Whether this message will not trigger push and desktop notifications */
SuppressNotifications = 1 << 12,
}
+4
View File
@@ -7,3 +7,7 @@ export function snowflakeToBigint(snowflake: BigString): bigint {
export function bigintToSnowflake(snowflake: BigString): string {
return snowflake === 0n ? '' : snowflake.toString()
}
export function snowflakeToTimestamp(id: bigint): number {
return Number(id / 4194304n + 1420070400000n)
}