diff --git a/packages/bot/src/transformers.ts b/packages/bot/src/transformers.ts index 57ecfbe3d..689318c4b 100644 --- a/packages/bot/src/transformers.ts +++ b/packages/bot/src/transformers.ts @@ -236,244 +236,7 @@ import { transformWelcomeScreen } from './transformers/welcomeScreen.js' import { transformWidget } from './transformers/widget.js' import { transformWidgetSettings } from './transformers/widgetSettings.js' -export type Transformers = { - customizers: { - activity: (bot: Bot, payload: DiscordActivity, activity: Activity) => any - activityInstance: ( - bot: Bot, - payload: DiscordActivityInstance, - activityInstance: SetupDesiredProps, - ) => any - activityLocation: ( - bot: Bot, - payload: DiscordActivityLocation, - activityLocation: SetupDesiredProps, - ) => any - application: (bot: Bot, payload: DiscordApplication, application: Application, extra?: { shardId?: number }) => any - applicationCommand: (bot: Bot, payload: DiscordApplicationCommand, applicationCommand: ApplicationCommand) => any - applicationCommandOption: ( - bot: Bot, - payload: DiscordApplicationCommandOption, - applicationCommandOption: ApplicationCommandOption, - ) => any - applicationCommandOptionChoice: ( - bot: Bot, - payload: DiscordApplicationCommandOptionChoice, - applicationCommandOptionChoice: ApplicationCommandOptionChoice, - ) => any - applicationCommandPermission: ( - bot: Bot, - payload: DiscordGuildApplicationCommandPermissions, - applicationCommandPermission: GuildApplicationCommandPermissions, - ) => any - attachment: (bot: Bot, payload: DiscordAttachment, attachment: SetupDesiredProps) => any - auditLogEntry: (bot: Bot, payload: DiscordAuditLogEntry, auditLogEntry: AuditLogEntry) => any - automodActionExecution: ( - bot: Bot, - payload: DiscordAutoModerationActionExecution, - automodActionExecution: AutoModerationActionExecution, - ) => any - automodRule: (bot: Bot, payload: DiscordAutoModerationRule, automodRule: AutoModerationRule) => any - avatarDecorationData: ( - bot: Bot, - payload: DiscordAvatarDecorationData, - avatarDecorationData: SetupDesiredProps, - ) => any - channel: ( - bot: Bot, - payload: DiscordChannel, - channel: SetupDesiredProps, - extra?: { guildId?: bigint }, - ) => any - collectibles: (bot: Bot, payload: DiscordCollectibles, collectibles: SetupDesiredProps) => any - component: (bot: Bot, payload: DiscordMessageComponent, component: Component) => any - defaultReactionEmoji: ( - bot: Bot, - payload: DiscordDefaultReactionEmoji, - defaultReactionEmoji: SetupDesiredProps, - ) => any - embed: (bot: Bot, payload: DiscordEmbed, embed: Embed) => any - emoji: (bot: Bot, payload: DiscordEmoji, emoji: SetupDesiredProps) => any - entitlement: (bot: Bot, payload: DiscordEntitlement, entitlement: SetupDesiredProps) => any - forumTag: (bot: Bot, payload: DiscordForumTag, forumTag: SetupDesiredProps) => any - gatewayBot: (bot: Bot, payload: DiscordGetGatewayBot, getGatewayBot: GetGatewayBot) => any - guild: ( - bot: Bot, - payload: DiscordGuild, - guild: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - guildOnboarding: ( - bot: Bot, - payload: DiscordGuildOnboarding, - onboarding: SetupDesiredProps, - ) => any - guildOnboardingPrompt: ( - bot: Bot, - payload: DiscordGuildOnboardingPrompt, - onboardingPrompt: SetupDesiredProps, - ) => any - guildOnboardingPromptOption: ( - bot: Bot, - payload: DiscordGuildOnboardingPromptOption, - onboardingPromptOption: SetupDesiredProps, - ) => any - incidentsData: ( - bot: Bot, - payload: DiscordIncidentsData, - incidentsData: SetupDesiredProps, - ) => any - integration: (bot: Bot, payload: DiscordIntegrationCreateUpdate, integration: Integration) => any - interaction: ( - bot: Bot, - payload: DiscordInteraction, - interaction: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - interactionCallback: ( - bot: Bot, - payload: DiscordInteractionCallback, - interactionCallback: SetupDesiredProps, - ) => any - interactionCallbackResponse: ( - bot: Bot, - payload: DiscordInteractionCallbackResponse, - interactionCallbackResponse: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - interactionDataOptions: (bot: Bot, payload: DiscordInteractionDataOption, interactionDataOptions: InteractionDataOption) => any - interactionDataResolved: ( - bot: Bot, - payload: DiscordInteractionDataResolved, - interactionDataResolved: InteractionDataResolved, - extra?: { shardId?: number; guildId?: bigint }, - ) => any - interactionResource: ( - bot: Bot, - payload: DiscordInteractionResource, - interactionResource: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - invite: ( - bot: Bot, - payload: DiscordInviteCreate | DiscordInviteMetadata, - invite: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - inviteStageInstance: ( - bot: Bot, - payload: DiscordInviteStageInstance, - inviteStageInstance: SetupDesiredProps, - extra?: { guildId?: bigint }, - ) => any - lobby: (bot: Bot, payload: DiscordLobby, lobby: SetupDesiredProps) => any - lobbyMember: (bot: Bot, payload: DiscordLobbyMember, lobbyMember: SetupDesiredProps) => any - mediaGalleryItem: (bot: Bot, payload: DiscordMediaGalleryItem, item: MediaGalleryItem) => any - member: ( - bot: Bot, - payload: DiscordMember, - member: SetupDesiredProps, - extra?: { guildId?: bigint; userId?: bigint }, - ) => any - message: ( - bot: Bot, - payload: DiscordMessage, - message: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - messageCall: (bot: Bot, payload: DiscordMessageCall, call: SetupDesiredProps) => any - messageInteractionMetadata: ( - bot: Bot, - payload: DiscordMessageInteractionMetadata, - metadata: SetupDesiredProps, - ) => any - messagePin: ( - bot: Bot, - payload: DiscordMessagePin, - call: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - messageSnapshot: ( - bot: Bot, - payload: DiscordMessageSnapshot, - messageSnapshot: SetupDesiredProps, - extra?: { shardId?: number }, - ) => any - nameplate: (bot: Bot, payload: DiscordNameplate, nameplate: SetupDesiredProps) => any - poll: (bot: Bot, payload: DiscordPoll, poll: SetupDesiredProps) => any - pollMedia: (bot: Bot, payload: DiscordPollMedia, pollMedia: SetupDesiredProps) => any - presence: (bot: Bot, payload: DiscordPresenceUpdate, presence: PresenceUpdate) => any - role: (bot: Bot, payload: DiscordRole, role: SetupDesiredProps, extra?: { guildId?: bigint }) => any - roleColors: (bot: Bot, payload: DiscordRoleColors, roleColors: SetupDesiredProps) => any - scheduledEvent: ( - bot: Bot, - payload: DiscordScheduledEvent, - scheduledEvent: SetupDesiredProps, - ) => any - scheduledEventRecurrenceRule: ( - bot: Bot, - payload: DiscordScheduledEventRecurrenceRule, - scheduledEvent: SetupDesiredProps, - ) => any - sku: (bot: Bot, payload: DiscordSku, sku: SetupDesiredProps) => any - soundboardSound: ( - bot: Bot, - payload: DiscordSoundboardSound, - soundboardSound: SetupDesiredProps, - ) => any - stageInstance: ( - bot: Bot, - payload: DiscordStageInstance, - stageInstance: SetupDesiredProps, - ) => any - sticker: (bot: Bot, payload: DiscordSticker, sticker: SetupDesiredProps) => any - stickerPack: (bot: Bot, payload: DiscordStickerPack, stickerPack: StickerPack) => any - subscription: (bot: Bot, payload: DiscordSubscription, subscription: SetupDesiredProps) => any - team: (bot: Bot, payload: DiscordTeam, team: Team) => any - template: (bot: Bot, payload: DiscordTemplate, template: Template) => any - threadMember: (bot: Bot, payload: DiscordThreadMember, threadMember: ThreadMember, extra?: ThreadMemberTransformerExtra) => any - threadMemberGuildCreate: ( - bot: Bot, - payload: DiscordThreadMemberGuildCreate, - threadMemberGuildCreate: ThreadMemberGuildCreate, - ) => any - unfurledMediaItem: (bot: Bot, payload: DiscordUnfurledMediaItem, unfurledMediaItem: UnfurledMediaItem) => any - user: (bot: Bot, payload: DiscordUser, user: SetupDesiredProps) => any - userPrimaryGuild: ( - bot: Bot, - payload: DiscordUserPrimaryGuild, - userPrimaryGuild: SetupDesiredProps, - ) => any - voiceRegion: (bot: Bot, payload: DiscordVoiceRegion, voiceRegion: VoiceRegion) => any - voiceState: ( - bot: Bot, - payload: DiscordVoiceState, - voiceState: SetupDesiredProps, - extra?: { guildId?: bigint }, - ) => any - webhook: (bot: Bot, payload: DiscordWebhook, webhook: SetupDesiredProps) => any - welcomeScreen: (bot: Bot, payload: DiscordWelcomeScreen, welcomeScreen: WelcomeScreen) => any - widget: (bot: Bot, payload: DiscordGuildWidget, widget: GuildWidget) => any - widgetSettings: (bot: Bot, payload: DiscordGuildWidgetSettings, widgetSettings: GuildWidgetSettings) => any - } - desiredProperties: TransformersDesiredProperties - reverse: { - activity: (bot: Bot, payload: Activity) => DiscordActivity - allowedMentions: (bot: Bot, payload: AllowedMentions) => DiscordAllowedMentions - application: (bot: Bot, payload: Application) => DiscordApplication - applicationCommand: (bot: Bot, payload: ApplicationCommand) => DiscordApplicationCommand - applicationCommandOption: (bot: Bot, payload: ApplicationCommandOption) => DiscordApplicationCommandOption - applicationCommandOptionChoice: (bot: Bot, payload: ApplicationCommandOptionChoice) => DiscordApplicationCommandOptionChoice - attachment: (bot: Bot, payload: SetupDesiredProps) => DiscordAttachment - component: (bot: Bot, payload: Component) => DiscordMessageComponent - embed: (bot: Bot, payload: Embed) => DiscordEmbed - mediaGalleryItem: (bot: Bot, payload: MediaGalleryItem) => DiscordMediaGalleryItem - member: (bot: Bot, payload: SetupDesiredProps) => DiscordMember - snowflake: (snowflake: BigString) => string - team: (bot: Bot, payload: Team) => DiscordTeam - unfurledMediaItem: (bot: Bot, payload: UnfurledMediaItem) => DiscordUnfurledMediaItem - user: (bot: Bot, payload: SetupDesiredProps) => DiscordUser - } +export type TransformerFunctions = { activity: TransformerFunction activityInstance: TransformerFunction activityLocation: TransformerFunction @@ -513,15 +276,8 @@ export type Transformers guildOnboarding: TransformerFunction guildOnboardingPrompt: TransformerFunction - guildOnboardingPromptOption: TransformerFunction< - TProps, - TBehavior, - DiscordGuildOnboardingPromptOption, - GuildOnboardingPromptOption, - {}, - 'unchanged' - > - incidentsData: TransformerFunction + guildOnboardingPromptOption: TransformerFunction + incidentsData: TransformerFunction integration: TransformerFunction interaction: TransformerFunction interactionCallback: TransformerFunction @@ -543,7 +299,7 @@ export type Transformers interactionResource: TransformerFunction invite: TransformerFunction - inviteStageInstance: TransformerFunction + inviteStageInstance: TransformerFunction lobby: TransformerFunction lobbyMember: TransformerFunction mediaGalleryItem: TransformerFunction @@ -563,7 +319,6 @@ export type Transformers sku: TransformerFunction soundboardSound: TransformerFunction - snowflake: (snowflake: BigString) => bigint stageInstance: TransformerFunction sticker: TransformerFunction stickerPack: TransformerFunction @@ -583,6 +338,32 @@ export type Transformers } +export type Transformers = TransformerFunctions< + TProps, + TBehavior +> & { + customizers: TransformerCustomizers + desiredProperties: TransformersDesiredProperties + reverse: { + activity: (bot: Bot, payload: Activity) => DiscordActivity + allowedMentions: (bot: Bot, payload: AllowedMentions) => DiscordAllowedMentions + application: (bot: Bot, payload: Application) => DiscordApplication + applicationCommand: (bot: Bot, payload: ApplicationCommand) => DiscordApplicationCommand + applicationCommandOption: (bot: Bot, payload: ApplicationCommandOption) => DiscordApplicationCommandOption + applicationCommandOptionChoice: (bot: Bot, payload: ApplicationCommandOptionChoice) => DiscordApplicationCommandOptionChoice + attachment: (bot: Bot, payload: SetupDesiredProps) => DiscordAttachment + component: (bot: Bot, payload: Component) => DiscordMessageComponent + embed: (bot: Bot, payload: Embed) => DiscordEmbed + mediaGalleryItem: (bot: Bot, payload: MediaGalleryItem) => DiscordMediaGalleryItem + member: (bot: Bot, payload: SetupDesiredProps) => DiscordMember + snowflake: (snowflake: BigString) => string + team: (bot: Bot, payload: Team) => DiscordTeam + unfurledMediaItem: (bot: Bot, payload: UnfurledMediaItem) => DiscordUnfurledMediaItem + user: (bot: Bot, payload: SetupDesiredProps) => DiscordUser + } + snowflake: (snowflake: BigString) => bigint +} + const defaultCustomizer = (_bot: unknown, _payload: unknown, structure: unknown) => structure export function createTransformers( @@ -780,3 +561,35 @@ export type TransformerFunction< : TKind extends 'transform' ? TransformProperty : TTransformed + +export type TransformerCustomizerFunction< + TProps extends TransformersDesiredProperties, + TBehavior extends DesiredPropertiesBehavior, + TPayload, + TTransformed, + TExtra = {}, +> = (bot: Bot, payload: TPayload, transformed: TTransformed, extra?: TExtra) => any + +export type TransformerCustomizers = { + [K in keyof TransformerFunctions]: TransformerFunctions[K] extends TransformerFunction< + TProps, + TBehavior, + infer TPayload, + infer _TTransformed, + infer TExtra, + infer _TKind + > + ? TransformerCustomizerFunction< + TProps, + TBehavior, + TPayload, + // We use ReturnType instead of inferring the transformed value so we don't need to do the logic on the kind as well + ReturnType[K]>, + BigStringsToBigints + > + : 'ERROR: Invalid transformer found' +} + +export type BigStringsToBigints = { + [K in keyof T]: BigString extends T[K] ? bigint : T[K] +} diff --git a/packages/bot/src/transformers/interaction.ts b/packages/bot/src/transformers/interaction.ts index 956cf60f5..5811520be 100644 --- a/packages/bot/src/transformers/interaction.ts +++ b/packages/bot/src/transformers/interaction.ts @@ -13,7 +13,7 @@ import { } from '@discordeno/types' import { Collection } from '@discordeno/utils' import type { Bot } from '../bot.js' -import type { InteractionResolvedDataChannel, InteractionResolvedDataMember } from '../commandOptionsParser.js' +import type { InteractionResolvedDataChannel } from '../commandOptionsParser.js' import type { CompleteDesiredProperties, DesiredPropertiesBehavior, @@ -22,15 +22,12 @@ import type { TransformProperty, } from '../desiredProperties.js' import type { - Attachment, Interaction, InteractionCallback, InteractionCallbackResponse, InteractionDataOption, InteractionDataResolved, InteractionResource, - Role, - User, } from './types.js' // Assume we have all desired properties for this or else typescript will get very confused for the return types of these functions. @@ -224,60 +221,67 @@ export function transformInteractionDataResolved( payload: DiscordInteractionDataResolved, extra?: { shardId?: number; guildId?: BigString }, ): TransformProperty { - const transformed: InteractionDataResolved = {} + const transformed: TransformProperty = {} if (payload.messages) { transformed.messages = new Collection( - Object.entries(payload.messages).map(([_id, value]) => { + Object.entries(payload.messages).map(([key, value]) => { // @ts-expect-error TODO: Deal with partials - const message = bot.transformers.message(bot, value, { shardId: extra?.shardId }) as Message - return [message.id, message] + const message = bot.transformers.message(bot, value, { shardId: extra?.shardId }) + const id = bot.transformers.snowflake(key) + + return [id, message] }), ) } if (payload.users) { transformed.users = new Collection( - Object.entries(payload.users).map(([_id, value]) => { - const user = bot.transformers.user(bot, value) as User - return [user.id, user] + Object.entries(payload.users).map(([key, value]) => { + const user = bot.transformers.user(bot, value) + const id = bot.transformers.snowflake(key) + + return [id, user] }), ) } if (extra?.guildId && payload.members) { transformed.members = new Collection( - Object.entries(payload.members).map(([id, value]) => { + Object.entries(payload.members).map(([key, value]) => { // @ts-expect-error TODO: Deal with partials, value is missing 2 values but the transformer can handle it, despite what the types says const member = bot.transformers.member(bot, value, { guildId: extra.guildId, - userId: bot.transformers.snowflake(id), - }) as InteractionResolvedDataMember + userId: bot.transformers.snowflake(key), + }) + const id = bot.transformers.snowflake(key) - // We need to tell TS that we are sure the id is a bigint - return [member.id as bigint, member] + return [id, member] }), ) } if (extra?.guildId && payload.roles) { transformed.roles = new Collection( - Object.entries(payload.roles).map(([_id, value]) => { - const role = bot.transformers.role(bot, value, { guildId: extra.guildId }) as Role - return [role.id, role] + Object.entries(payload.roles).map(([key, value]) => { + const role = bot.transformers.role(bot, value, { guildId: extra.guildId }) + const id = bot.transformers.snowflake(key) + + return [id, role] }), ) } if (payload.channels) { transformed.channels = new Collection( - Object.entries(payload.channels).map(([_id, value]) => { - const channel = bot.transformers.channel(bot, value) as unknown as InteractionResolvedDataChannel< + Object.entries(payload.channels).map(([key, value]) => { + const channel = bot.transformers.channel(bot, value) as InteractionResolvedDataChannel< TransformersDesiredProperties, - DesiredPropertiesBehavior + DesiredPropertiesBehavior.RemoveKey > - // We need to tell TS that we are sure the id is a bigint - return [channel.id as bigint, channel] + const id = bot.transformers.snowflake(key) + + return [id, channel] }), ) } @@ -286,7 +290,8 @@ export function transformInteractionDataResolved( transformed.attachments = new Collection( Object.entries(payload.attachments).map(([key, value]) => { const id = bot.transformers.snowflake(key) - const attachment = bot.transformers.attachment(bot, value) as Attachment + const attachment = bot.transformers.attachment(bot, value) + return [id, attachment] }), ) diff --git a/packages/bot/src/transformers/threadMember.ts b/packages/bot/src/transformers/threadMember.ts index bc15e49b4..6e7fca576 100644 --- a/packages/bot/src/transformers/threadMember.ts +++ b/packages/bot/src/transformers/threadMember.ts @@ -16,7 +16,9 @@ export function transformThreadMember(bot: Bot, payload: DiscordThreadMember, ex : undefined, } as ThreadMember - return bot.transformers.customizers.threadMember(bot, payload, threadMember, extra) + return bot.transformers.customizers.threadMember(bot, payload, threadMember, { + guildId: extra?.guildId ? bot.transformers.snowflake(extra?.guildId) : undefined, + }) } export interface ThreadMemberTransformerExtra {