police-bot/src/discord/message.ts

235 lines
6.5 KiB
TypeScript

import { fetchDiscord } from "./core";
/**
* Represents a message sent in a channel within Discord.
* This is a partial interface based on the Discord API documentation.
*/
export interface Message {
id: string;
channel_id: string;
author: any; // User object
content: string;
timestamp: string; // ISO8601 timestamp
edited_timestamp: string | null; // ISO8601 timestamp
tts: boolean;
mention_everyone: boolean;
mentions: any[]; // array of user objects
mention_roles: string[]; // array of role object ids
mention_channels?: any[]; // array of channel mention objects
attachments: any[]; // array of attachment objects
embeds: any[]; // array of embed objects
reactions?: any[]; // array of reaction objects
nonce?: number | string;
pinned: boolean;
webhook_id?: string;
type: number;
activity?: any; // message activity object
application?: any; // partial application object
application_id?: string;
flags?: number;
message_reference?: any; // message reference object
referenced_message?: Message | null;
interaction?: any; // message interaction object
thread?: any; // channel object
components?: any[]; // array of message components
sticker_items?: any[]; // array of message sticker item objects
stickers?: any[]; // array of sticker objects
position?: number;
role_subscription_data?: any; // role subscription data object
resolved?: any;
}
/**
* Retrieves the messages in a channel.
* @param channelId The ID of the channel.
* @param options Options for fetching messages.
* @returns An array of message objects.
*/
export const getChannelMessages = async (
channelId: string,
options?: {
around?: string;
before?: string;
after?: string;
limit?: number;
},
): Promise<Message[]> => {
const query = new URLSearchParams();
if (options?.around) query.append("around", options.around);
if (options?.before) query.append("before", options.before);
if (options?.after) query.append("after", options.after);
if (options?.limit) query.append("limit", String(options.limit));
const queryString = query.toString();
const path = `/channels/${channelId}/messages${queryString ? `?${queryString}` : ""}`;
const res = await fetchDiscord(path);
return res.json();
};
/**
* Retrieves a specific message in the channel.
* @param channelId The ID of the channel.
* @param messageId The ID of the message.
* @returns A message object.
*/
export const getChannelMessage = async (
channelId: string,
messageId: string,
): Promise<Message> => {
const path = `/channels/${channelId}/messages/${messageId}`;
const res = await fetchDiscord(path);
return res.json();
};
export interface CreateMessageParams {
content?: string;
tts?: boolean;
embeds?: any[];
allowed_mentions?: any;
message_reference?: any;
components?: any[];
sticker_ids?: string[];
files?: any[];
payload_json?: string;
attachments?: any[];
flags?: number;
}
/**
* Post a message to a guild text or DM channel.
* @param channelId The ID of the channel.
* @param data The message data.
* @returns The created message object.
*/
export const createMessage = async (
channelId: string,
data: CreateMessageParams,
): Promise<Message> => {
const path = `/channels/${channelId}/messages`;
const res = await fetchDiscord(path, {
method: "POST",
body: JSON.stringify(data),
});
return res.json();
};
export interface EditMessageParams {
content?: string;
embeds?: any[];
flags?: number;
allowed_mentions?: any;
components?: any[];
files?: any[];
payload_json?: string;
attachments?: any[];
}
/**
* Edit a previously sent message.
* @param channelId The ID of the channel.
* @param messageId The ID of the message to edit.
* @param data The new message data.
* @returns The updated message object.
*/
export const editMessage = async (
channelId: string,
messageId: string,
data: EditMessageParams,
): Promise<Message> => {
const path = `/channels/${channelId}/messages/${messageId}`;
const res = await fetchDiscord(path, {
method: "PATCH",
body: JSON.stringify(data),
});
return res.json();
};
/**
* Delete a message.
* @param channelId The ID of the channel.
* @param messageId The ID of the message to delete.
*/
export const deleteMessage = async (
channelId: string,
messageId: string,
): Promise<void> => {
const path = `/channels/${channelId}/messages/${messageId}`;
await fetchDiscord(path, {
method: "DELETE",
});
};
/**
* Delete multiple messages in a single request.
* @param channelId The ID of the channel.
* @param messageIds An array of message IDs to delete.
*/
export const bulkDeleteMessages = async (
channelId: string,
messageIds: string[],
): Promise<void> => {
const path = `/channels/${channelId}/messages/bulk-delete`;
await fetchDiscord(path, {
method: "POST",
body: JSON.stringify({ messages: messageIds }),
});
};
/**
* Create a reaction for the message.
* @param channelId The ID of the channel.
* @param messageId The ID of the message.
* @param emoji The emoji to react with.
*/
export const addReaction = async (
channelId: string,
messageId: string,
emoji: string,
): Promise<void> => {
const path = `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(
emoji,
)}/@me`;
await fetchDiscord(path, { method: "PUT" });
};
/**
* Get a list of users that reacted with this emoji.
* @param channelId The ID of the channel.
* @param messageId The ID of the message.
* @param emoji The emoji.
* @param options Options for fetching reactions.
* @returns A list of user objects.
*/
export const getReactions = async (
channelId: string,
messageId: string,
emoji: string,
options?: { after?: string; limit?: number },
): Promise<any[]> => {
const query = new URLSearchParams();
if (options?.after) query.append("after", options.after);
if (options?.limit) query.append("limit", String(options.limit ?? 100));
const queryString = query.toString();
const path = `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(
emoji,
)}${queryString ? `?${queryString}` : ""}`;
const res = await fetchDiscord(path);
return res.json();
};
export const listReactionUsersMulti = async (
channelId: string,
messageId: string,
emojis: string[],
) => {
const results = await Promise.all(
emojis.map((e) => getReactions(channelId, messageId, e)),
);
const byId = new Map<string, any>();
for (const arr of results) {
for (const u of arr) byId.set(u.id, u); // de-dupe across variants
}
return Array.from(byId.values());
};