feat(types,rest,bot): Updated message pin endpoints (#4228)

* feat: Updated message pin endpoints

* Apply suggestions from code review

Co-authored-by: Link <lts20050703@gmail.com>

---------

Co-authored-by: Link <lts20050703@gmail.com>
This commit is contained in:
Fleny
2025-07-12 09:30:35 +02:00
committed by GitHub
co-authored by Link
parent cb8176c623
commit 612ac26ea7
11 changed files with 116 additions and 13 deletions
+7
View File
@@ -32,6 +32,7 @@ import type {
MessageCall, MessageCall,
MessageInteraction, MessageInteraction,
MessageInteractionMetadata, MessageInteractionMetadata,
MessagePin,
MessageReference, MessageReference,
MessageSnapshot, MessageSnapshot,
Nameplate, Nameplate,
@@ -92,6 +93,7 @@ export interface TransformersObjects {
messageCall: MessageCall messageCall: MessageCall
messageInteraction: MessageInteraction messageInteraction: MessageInteraction
messageInteractionMetadata: MessageInteractionMetadata messageInteractionMetadata: MessageInteractionMetadata
messagePin: MessagePin
messageReference: MessageReference messageReference: MessageReference
messageSnapshot: MessageSnapshot messageSnapshot: MessageSnapshot
nameplate: Nameplate nameplate: Nameplate
@@ -544,6 +546,11 @@ export function createDesiredPropertiesObject<T extends RecursivePartial<Transfo
targetUser: defaultValue, targetUser: defaultValue,
...desiredProperties.messageInteractionMetadata, ...desiredProperties.messageInteractionMetadata,
}, },
messagePin: {
message: defaultValue,
pinnedAt: defaultValue,
...desiredProperties.messagePin,
},
messageInteraction: { messageInteraction: {
id: defaultValue, id: defaultValue,
member: defaultValue, member: defaultValue,
+17
View File
@@ -1,3 +1,5 @@
// biome-ignore lint/correctness/noUnusedImports: <explanation>
import type { RestManager } from '@discordeno/rest'
import type { import type {
AddDmRecipientOptions, AddDmRecipientOptions,
AddGuildMemberOptions, AddGuildMemberOptions,
@@ -68,6 +70,7 @@ import type {
ExecuteWebhook, ExecuteWebhook,
GetApplicationCommandPermissionOptions, GetApplicationCommandPermissionOptions,
GetBans, GetBans,
GetChannelPinsOptions,
GetEntitlements, GetEntitlements,
GetGroupDmOptions, GetGroupDmOptions,
GetGuildAuditLog, GetGuildAuditLog,
@@ -129,6 +132,7 @@ import type {
LobbyMember, LobbyMember,
Member, Member,
Message, Message,
MessagePin,
Role, Role,
ScheduledEvent, ScheduledEvent,
Sku, Sku,
@@ -442,6 +446,14 @@ export function createBotHelpers<TProps extends TransformersDesiredProperties, T
getOriginalInteractionResponse: async (token) => { getOriginalInteractionResponse: async (token) => {
return bot.transformers.message(bot, { message: snakelize(await bot.rest.getOriginalInteractionResponse(token)), shardId: 0 }) return bot.transformers.message(bot, { message: snakelize(await bot.rest.getOriginalInteractionResponse(token)), shardId: 0 })
}, },
getChannelPins: async (channelId, options) => {
const res = snakelize(await bot.rest.getChannelPins(channelId, options))
return {
hasMore: res.has_more,
items: bot.transformers.messagePin(bot, res.items),
}
},
getPinnedMessages: async (channelId) => { getPinnedMessages: async (channelId) => {
return (await bot.rest.getPinnedMessages(channelId)).map((res) => bot.transformers.message(bot, { message: snakelize(res), shardId: 0 })) return (await bot.rest.getPinnedMessages(channelId)).map((res) => bot.transformers.message(bot, { message: snakelize(res), shardId: 0 }))
}, },
@@ -1007,6 +1019,11 @@ export type BotHelpers<TProps extends TransformersDesiredProperties, TBehavior e
getStickerPack: (stickerPackId: BigString) => Promise<StickerPack> getStickerPack: (stickerPackId: BigString) => Promise<StickerPack>
getStickerPacks: () => Promise<StickerPack[]> getStickerPacks: () => Promise<StickerPack[]>
getOriginalInteractionResponse: (token: string) => Promise<SetupDesiredProps<Message, TProps, TBehavior>> getOriginalInteractionResponse: (token: string) => Promise<SetupDesiredProps<Message, TProps, TBehavior>>
getChannelPins: (
channelId: BigString,
options?: GetChannelPinsOptions,
) => Promise<{ items: SetupDesiredProps<MessagePin, TProps, TBehavior>; hasMore: boolean }>
/** @deprecated Use {@link BotHelpers.getChannelPins} instead */
getPinnedMessages: (channelId: BigString) => Promise<SetupDesiredProps<Message, TProps, TBehavior>[]> getPinnedMessages: (channelId: BigString) => Promise<SetupDesiredProps<Message, TProps, TBehavior>[]>
getPrivateArchivedThreads: (channelId: BigString, options?: ListArchivedThreads) => Promise<Camelize<DiscordListArchivedThreads>> getPrivateArchivedThreads: (channelId: BigString, options?: ListArchivedThreads) => Promise<Camelize<DiscordListArchivedThreads>>
getPrivateJoinedArchivedThreads: (channelId: BigString, options?: ListArchivedThreads) => Promise<Camelize<DiscordListArchivedThreads>> getPrivateJoinedArchivedThreads: (channelId: BigString, options?: ListArchivedThreads) => Promise<Camelize<DiscordListArchivedThreads>>
+4
View File
@@ -50,6 +50,7 @@ import type {
DiscordMessageCall, DiscordMessageCall,
DiscordMessageComponent, DiscordMessageComponent,
DiscordMessageInteractionMetadata, DiscordMessageInteractionMetadata,
DiscordMessagePin,
DiscordMessageSnapshot, DiscordMessageSnapshot,
DiscordNameplate, DiscordNameplate,
DiscordPoll, DiscordPoll,
@@ -132,6 +133,7 @@ import {
type Message, type Message,
type MessageCall, type MessageCall,
type MessageInteractionMetadata, type MessageInteractionMetadata,
type MessagePin,
type MessageSnapshot, type MessageSnapshot,
type Nameplate, type Nameplate,
type Poll, type Poll,
@@ -369,6 +371,7 @@ export type Transformers<TProps extends TransformersDesiredProperties, TBehavior
payload: DiscordMessageInteractionMetadata, payload: DiscordMessageInteractionMetadata,
metadata: SetupDesiredProps<MessageInteractionMetadata, TProps, TBehavior>, metadata: SetupDesiredProps<MessageInteractionMetadata, TProps, TBehavior>,
) => any ) => any
messagePin: (bot: Bot<TProps, TBehavior>, payload: DiscordMessagePin, call: SetupDesiredProps<MessagePin, TProps, TBehavior>) => any
messageSnapshot: ( messageSnapshot: (
bot: Bot<TProps, TBehavior>, bot: Bot<TProps, TBehavior>,
payload: DiscordMessageSnapshot, payload: DiscordMessageSnapshot,
@@ -526,6 +529,7 @@ export type Transformers<TProps extends TransformersDesiredProperties, TBehavior
bot: Bot<TProps, TBehavior>, bot: Bot<TProps, TBehavior>,
payload: DiscordMessageInteractionMetadata, payload: DiscordMessageInteractionMetadata,
) => SetupDesiredProps<MessageInteractionMetadata, TProps, TBehavior> ) => SetupDesiredProps<MessageInteractionMetadata, TProps, TBehavior>
messagePin: (bot: Bot<TProps, TBehavior>, payload: DiscordMessagePin) => SetupDesiredProps<MessagePin, TProps, TBehavior>
messageSnapshot: ( messageSnapshot: (
bot: Bot<TProps, TBehavior>, bot: Bot<TProps, TBehavior>,
payload: { messageSnapshot: DiscordMessageSnapshot; shardId: number }, payload: { messageSnapshot: DiscordMessageSnapshot; shardId: number },
+12
View File
@@ -4,6 +4,7 @@ import {
type DiscordMessage, type DiscordMessage,
type DiscordMessageCall, type DiscordMessageCall,
type DiscordMessageInteractionMetadata, type DiscordMessageInteractionMetadata,
type DiscordMessagePin,
type DiscordMessageSnapshot, type DiscordMessageSnapshot,
MessageFlags, MessageFlags,
} from '@discordeno/types' } from '@discordeno/types'
@@ -13,6 +14,7 @@ import {
type Message, type Message,
type MessageCall, type MessageCall,
type MessageInteractionMetadata, type MessageInteractionMetadata,
type MessagePin,
type MessageSnapshot, type MessageSnapshot,
snowflakeToTimestamp, snowflakeToTimestamp,
} from '../index.js' } from '../index.js'
@@ -261,6 +263,16 @@ export function transformMessage(
return bot.transformers.customizers.message(bot, payload.message, message) return bot.transformers.customizers.message(bot, payload.message, message)
} }
export function transformMessagePin(bot: InternalBot, payload: DiscordMessagePin): MessagePin {
const props = bot.transformers.desiredProperties.messagePin
const messagePin = {} as MessagePin
if (props.pinnedAt && payload.pinned_at) messagePin.pinnedAt = Date.parse(payload.pinned_at)
if (props.message && payload.message) messagePin.message = bot.transformers.message(bot, { message: payload.message, shardId: 0 })
return bot.transformers.customizers.messagePin(bot, payload, messagePin)
}
export function transformMessageSnapshot( export function transformMessageSnapshot(
bot: InternalBot, bot: InternalBot,
payload: { messageSnapshot: DiscordMessageSnapshot; shardId: number }, payload: { messageSnapshot: DiscordMessageSnapshot; shardId: number },
+7
View File
@@ -1329,6 +1329,13 @@ export interface MessageCall {
endedTimestamp: number endedTimestamp: number
} }
export interface MessagePin {
/** the time the message was pinned */
pinnedAt: number
/** the pinned message */
message: Message
}
export interface Reaction { export interface Reaction {
/** Whether the current user reacted using this emoji */ /** Whether the current user reacted using this emoji */
me: boolean me: boolean
+6 -2
View File
@@ -1330,6 +1330,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.get<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), { unauthorized: true }) return await rest.get<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), { unauthorized: true })
}, },
async getChannelPins(channelId, options) {
return await rest.get(rest.routes.channels.messagePins(channelId, options))
},
async getPinnedMessages(channelId) { async getPinnedMessages(channelId) {
return await rest.get<DiscordMessage[]>(rest.routes.channels.pins(channelId)) return await rest.get<DiscordMessage[]>(rest.routes.channels.pins(channelId))
}, },
@@ -1590,7 +1594,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
}, },
async pinMessage(channelId, messageId, reason) { async pinMessage(channelId, messageId, reason) {
await rest.put(rest.routes.channels.pin(channelId, messageId), { reason }) await rest.put(rest.routes.channels.messagePin(channelId, messageId), { reason })
}, },
async pruneMembers(guildId, body, reason) { async pruneMembers(guildId, body, reason) {
@@ -1621,7 +1625,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
}, },
async unpinMessage(channelId, messageId, reason) { async unpinMessage(channelId, messageId, reason) {
await rest.delete(rest.routes.channels.pin(channelId, messageId), { reason }) await rest.delete(rest.routes.channels.messagePin(channelId, messageId), { reason })
}, },
async triggerTypingIndicator(channelId) { async triggerTypingIndicator(channelId) {
+13
View File
@@ -48,6 +48,19 @@ export function createRoutes(): RestRoutes {
pins: (channelId) => { pins: (channelId) => {
return `/channels/${channelId}/pins` return `/channels/${channelId}/pins`
}, },
messagePins: (channelId, options) => {
let url = `/channels/${channelId}/messages/pins?`
if (options) {
if (options.before) url += `before=${options.before}`
if (options.limit) url += `&limit=${options.limit}`
}
return url
},
messagePin: (channelId, messageId) => {
return `/channels/${channelId}/messages/pins/${messageId}`
},
reactions: { reactions: {
bot: (channelId, messageId, emoji) => { bot: (channelId, messageId, emoji) => {
return `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/@me` return `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/@me`
+22 -10
View File
@@ -48,6 +48,7 @@ import type {
DiscordEntitlement, DiscordEntitlement,
DiscordFollowedChannel, DiscordFollowedChannel,
DiscordGetAnswerVotesResponse, DiscordGetAnswerVotesResponse,
DiscordGetChannelPins,
DiscordGetGatewayBot, DiscordGetGatewayBot,
DiscordGuild, DiscordGuild,
DiscordGuildApplicationCommandPermissions, DiscordGuildApplicationCommandPermissions,
@@ -103,6 +104,7 @@ import type {
FileContent, FileContent,
GetApplicationCommandPermissionOptions, GetApplicationCommandPermissionOptions,
GetBans, GetBans,
GetChannelPinsOptions,
GetEntitlements, GetEntitlements,
GetGroupDmOptions, GetGroupDmOptions,
GetGuildAuditLog, GetGuildAuditLog,
@@ -2079,6 +2081,21 @@ export interface RestManager {
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#get-original-interaction-response} * @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#get-original-interaction-response}
*/ */
getOriginalInteractionResponse: (token: string) => Promise<Camelize<DiscordMessage>> getOriginalInteractionResponse: (token: string) => Promise<Camelize<DiscordMessage>>
/**
* Retrieves the list of pins in a channel.
*
* @param channelId - The ID of the channel to get the pins for.
* @param options - The options for the fetching of the pins.
* @returns A {@link DiscordGetChannelPins} objects
*
* @remarks
* Requires the `VIEW_CHANNEL` permission.
*
* If the user is missing the `READ_MESSAGE_HISTORY` permission in the channel, then no pins will be returned.
*
* @see {@link https://discord.com/developers/docs/resources/message#get-channel-pins}
*/
getChannelPins: (channelId: BigString, options?: GetChannelPinsOptions) => Promise<Camelize<DiscordGetChannelPins>>
/** /**
* Gets the pinned messages for a channel. * Gets the pinned messages for a channel.
* *
@@ -2091,7 +2108,8 @@ export interface RestManager {
* If getting a message from a guild channel: * If getting a message from a guild channel:
* - Requires the `READ_MESSAGE_HISTORY` permission. * - Requires the `READ_MESSAGE_HISTORY` permission.
* *
* @see {@link https://discord.com/developers/docs/resources/channel#get-pinned-messages} * @see {@link https://discord.com/developers/docs/resources/message#get-pinned-messages-deprecated}
* @deprecated Use {@link getChannelPins} instead.
*/ */
getPinnedMessages: (channelId: BigString) => Promise<Camelize<DiscordMessage>[]> getPinnedMessages: (channelId: BigString) => Promise<Camelize<DiscordMessage>[]>
/** /**
@@ -2896,15 +2914,11 @@ export interface RestManager {
* @param {string} [reason] - An optional reason for the action, to be included in the audit log. * @param {string} [reason] - An optional reason for the action, to be included in the audit log.
* *
* @remarks * @remarks
* Requires that the bot user be able to see the contents of the channel in which the messages were posted.
*
* Requires the `MANAGE_MESSAGES` permission. * Requires the `MANAGE_MESSAGES` permission.
* *
* ⚠️ There can only be at max 50 messages pinned in a channel.
*
* Fires a _Channel Pins Update_ event. * Fires a _Channel Pins Update_ event.
* *
* @see {@link https://discord.com/developers/docs/resources/channel#pin-message} * @see {@link https://discord.com/developers/docs/resources/message#pin-message}
*/ */
pinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void> pinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void>
/** /**
@@ -2957,20 +2971,18 @@ export interface RestManager {
*/ */
unbanMember: (guildId: BigString, userId: BigString, reason?: string) => Promise<void> unbanMember: (guildId: BigString, userId: BigString, reason?: string) => Promise<void>
/** /**
* Unpins a pinned message in a channel. * Unpin a message in a channel.
* *
* @param channelId - The ID of the channel where the message is pinned. * @param channelId - The ID of the channel where the message is pinned.
* @param messageId - The ID of the message to unpin. * @param messageId - The ID of the message to unpin.
* @param {string} [reason] - An optional reason for the action, to be included in the audit log. * @param {string} [reason] - An optional reason for the action, to be included in the audit log.
* *
* @remarks * @remarks
* Requires that the bot user be able to see the contents of the channel in which the messages were posted.
*
* Requires the `MANAGE_MESSAGES` permission. * Requires the `MANAGE_MESSAGES` permission.
* *
* Fires a _Channel Pins Update_ event. * Fires a _Channel Pins Update_ event.
* *
* @see {@link https://discord.com/developers/docs/resources/channel#unpin-message} * @see {@link https://discord.com/developers/docs/resources/message#unpin-message}
*/ */
unpinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void> unpinMessage: (channelId: BigString, messageId: BigString, reason?: string) => Promise<void>
/** /**
+6 -1
View File
@@ -1,6 +1,7 @@
import type { import type {
BigString, BigString,
GetBans, GetBans,
GetChannelPinsOptions,
GetEntitlements, GetEntitlements,
GetGuildAuditLog, GetGuildAuditLog,
GetGuildPruneCountQuery, GetGuildPruneCountQuery,
@@ -45,8 +46,12 @@ export interface RestRoutes {
dmRecipient: (channelId: BigString, userId: BigString) => string dmRecipient: (channelId: BigString, userId: BigString) => string
/** Route for handling a specific pin. */ /** Route for handling a specific pin. */
pin: (channelId: BigString, messageId: BigString) => string pin: (channelId: BigString, messageId: BigString) => string
/** Route for handling a channels pins. */ /** Route for handling a channel's pins. */
pins: (channelId: BigString) => string pins: (channelId: BigString) => string
/** Route for handling a channel's pins. */
messagePins: (channelId: BigString, options?: GetChannelPinsOptions) => string
/** Route for handling a specific pin. */
messagePin: (channelId: BigString, messageId: BigString) => string
/** Route for non-specific webhook in a channel. */ /** Route for non-specific webhook in a channel. */
webhooks: (channelId: BigString) => string webhooks: (channelId: BigString) => string
/** Route for a specific channel. */ /** Route for a specific channel. */
+14
View File
@@ -532,6 +532,14 @@ export interface DiscordAllowedMentions {
// TODO: Implement RoleSubscriptionData https://discord.com/developers/docs/resources/message#role-subscription-data-object-role-subscription-data-object-structure // TODO: Implement RoleSubscriptionData https://discord.com/developers/docs/resources/message#role-subscription-data-object-role-subscription-data-object-structure
/** https://discord.com/developers/docs/resources/message#message-pin-object-message-pin-object-struture */
export interface DiscordMessagePin {
/** the time the message was pinned */
pinned_at: string
/** the pinned message */
message: DiscordMessage
}
/** https://discord.com/developers/docs/resources/message#create-message-jsonform-params */ /** https://discord.com/developers/docs/resources/message#create-message-jsonform-params */
export interface DiscordCreateMessage { export interface DiscordCreateMessage {
/** The message contents (up to 2000 characters) */ /** The message contents (up to 2000 characters) */
@@ -569,3 +577,9 @@ export enum DiscordReactionType {
Normal, Normal,
Burst, Burst,
} }
/** https://discord.com/developers/docs/resources/message#get-channel-pins-response-structure */
export interface DiscordGetChannelPins {
items: DiscordMessagePin
has_more: boolean
}
+8
View File
@@ -1392,6 +1392,14 @@ export interface EditMessage {
components?: MessageComponents components?: MessageComponents
} }
/** https://discord.com/developers/docs/resources/message#get-channel-pins-query-string-params */
export interface GetChannelPinsOptions {
/** Get messages pinned before this timestamp */
before?: string
/** Max number of pins to return (1-50), defaults to 50 */
limit?: number
}
/** Additional properties for https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions and https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions */ /** Additional properties for https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions and https://discord.com/developers/docs/interactions/application-commands#get-guild-application-command-permissions */
export interface GetApplicationCommandPermissionOptions { export interface GetApplicationCommandPermissionOptions {
/** Access token of the user. Requires the `applications.commands.permissions.update` scope */ /** Access token of the user. Requires the `applications.commands.permissions.update` scope */