mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-02 17:00:08 +00:00
add webhook functionality
This commit is contained in:
@@ -77,6 +77,8 @@ export const endpoints = {
|
||||
GUILD_VANITY_URL: (id: string) => `${GUILDS_BASE(id)}/vanity-url`,
|
||||
GUILD_WEBHOOKS: (id: string) => `${GUILDS_BASE(id)}/webhooks`,
|
||||
|
||||
WEBHOOK: (id: string, token: string) => `${baseEndpoints.BASE_URL}/webhooks/${id}/${token}`,
|
||||
|
||||
// User endpoints
|
||||
USER_AVATAR: (id: string, icon: string) =>
|
||||
`${baseEndpoints.CDN_URL}/avatars/${id}/${icon}`,
|
||||
|
||||
102
src/handlers/webhook.ts
Normal file
102
src/handlers/webhook.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
WebhookCreateOptions,
|
||||
WebhookPayload,
|
||||
ExecuteWebhookOptions,
|
||||
} from "../types/webhook.ts";
|
||||
import { botHasChannelPermissions } from "../utils/permissions.ts";
|
||||
import { Permissions } from "../types/permission.ts";
|
||||
import { Errors } from "../types/errors.ts";
|
||||
import { RequestManager } from "../module/requestManager.ts";
|
||||
import { endpoints } from "../constants/discord.ts";
|
||||
import { createMessage } from "../structures/message.ts";
|
||||
import { MessageCreateOptions } from "../types/message.ts";
|
||||
import { urlToBase64 } from "../utils/utils.ts";
|
||||
|
||||
/** Create a new webhook. Requires the MANAGE_WEBHOOKS permission. Returns a webhook object on success. Webhook names follow our naming restrictions that can be found in our Usernames and Nicknames documentation, with the following additional stipulations:
|
||||
*
|
||||
* Webhook names cannot be: 'clyde'
|
||||
*/
|
||||
export async function createWebhook(
|
||||
channelID: string,
|
||||
options: WebhookCreateOptions,
|
||||
) {
|
||||
if (
|
||||
!botHasChannelPermissions(
|
||||
channelID,
|
||||
[Permissions.MANAGE_WEBHOOKS],
|
||||
)
|
||||
) {
|
||||
throw new Error(Errors.MISSING_MANAGE_WEBHOOKS);
|
||||
}
|
||||
|
||||
if (
|
||||
// Specific usernames that discord does not allow
|
||||
options.name === "clyde" ||
|
||||
// Character limit checks. [...] checks are because of js unicode length handling
|
||||
[...options.name].length < 2 || [...options.name].length > 32
|
||||
) {
|
||||
throw new Error(Errors.INVALID_WEBHOOK_NAME);
|
||||
}
|
||||
|
||||
return RequestManager.post(
|
||||
endpoints.CHANNEL_WEBHOOKS(channelID),
|
||||
{
|
||||
...options,
|
||||
avatar: options.avatar ? await urlToBase64(options.avatar) : undefined,
|
||||
},
|
||||
) as Promise<WebhookPayload>;
|
||||
}
|
||||
|
||||
export async function executeWebhook(
|
||||
webhookID: string,
|
||||
webhookToken: string,
|
||||
options: ExecuteWebhookOptions,
|
||||
) {
|
||||
if (!options.content && !options.file && !options.embeds) {
|
||||
throw new Error(Errors.INVALID_WEBHOOK_OPTIONS);
|
||||
}
|
||||
|
||||
if (options.embeds && options.embeds.length > 10) {
|
||||
options.embeds.splice(10);
|
||||
}
|
||||
|
||||
if (options.mentions) {
|
||||
if (options.mentions.users?.length) {
|
||||
if (options.mentions.parse.includes("users")) {
|
||||
options.mentions.parse = options.mentions.parse.filter((p) =>
|
||||
p !== "users"
|
||||
);
|
||||
}
|
||||
|
||||
if (options.mentions.users.length > 100) {
|
||||
options.mentions.users = options.mentions.users.slice(0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.mentions.roles?.length) {
|
||||
if (options.mentions.parse.includes("roles")) {
|
||||
options.mentions.parse = options.mentions.parse.filter((p) =>
|
||||
p !== "roles"
|
||||
);
|
||||
}
|
||||
|
||||
if (options.mentions.roles.length > 100) {
|
||||
options.mentions.roles = options.mentions.roles.slice(0, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await RequestManager.post(
|
||||
`${endpoints.WEBHOOK(webhookID, webhookToken)}${
|
||||
options.wait ? "?wait=true" : ""
|
||||
}`,
|
||||
{
|
||||
...options,
|
||||
allowed_mentions: options.mentions,
|
||||
avatar_url: options.avatar_url,
|
||||
},
|
||||
);
|
||||
if (!options.wait) return;
|
||||
|
||||
return createMessage(result as MessageCreateOptions);
|
||||
}
|
||||
@@ -28,4 +28,6 @@ export enum Errors {
|
||||
REQUEST_UNKNOWN_ERROR = "REQUEST_UNKNOWN_ERROR",
|
||||
BOTS_HIGHEST_ROLE_TOO_LOW = "BOTS_HIGHEST_ROLE_TOO_LOW",
|
||||
CHANNEL_NOT_IN_GUILD = "CHANNEL_NOT_IN_GUILD",
|
||||
INVALID_WEBHOOK_NAME = "INVALID_WEBHOOK_NAME",
|
||||
INVALID_WEBHOOK_OPTIONS = "INVALID_WEBHOOK_OPTIONS",
|
||||
}
|
||||
|
||||
61
src/types/webhook.ts
Normal file
61
src/types/webhook.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { UserPayload } from "./guild.ts";
|
||||
import { Embed } from "./message.ts";
|
||||
|
||||
export interface WebhookPayload {
|
||||
/** The id of the webhook */
|
||||
id: string;
|
||||
/** The type of the webhook */
|
||||
type: WebhookType;
|
||||
/** The guild id this webhook is for */
|
||||
guild_id?: string;
|
||||
/** The channel id this webhook is for */
|
||||
channel_id: string;
|
||||
/** The user this webhook was created by(not returned when getting a webhook with its token) */
|
||||
user?: UserPayload;
|
||||
/** The default name of the webhook */
|
||||
name?: string;
|
||||
/** The default avatar of the webhook */
|
||||
avatar?: string;
|
||||
/** The secure token of the webhook(returned for Incoming Webhooks) */
|
||||
token?: string;
|
||||
}
|
||||
|
||||
export enum WebhookType {
|
||||
/** Incoming Webhooks can post messages to channels with a generated token */
|
||||
INCOMING = 1,
|
||||
/** Channel Follower Webhooks are internal webhooks used with Channel Following to post new messages into channels */
|
||||
CHANNEL_FOLLOWER = 2,
|
||||
}
|
||||
|
||||
export interface WebhookCreateOptions {
|
||||
/** Name of the webhook (1-80 characters) */
|
||||
name: string;
|
||||
/** Image url for avatar image for the default webhook avatar */
|
||||
avatar?: string;
|
||||
}
|
||||
|
||||
export interface ExecuteWebhookOptions {
|
||||
/** waits for server confirmation of message send before response, and returns the created message body (defaults to false; when false a message that is not saved does not return an error) */
|
||||
wait?: boolean;
|
||||
/** the message contents (up to 2000 characters) */
|
||||
content?: string;
|
||||
/** override the default username of the webhook */
|
||||
username?: string;
|
||||
/** override the default avatar of the webhook*/
|
||||
avatar_url?: string;
|
||||
/** true if this is a TTS message */
|
||||
tts?: boolean;
|
||||
/** file contents the contents of the file being sent one of content, file, embeds */
|
||||
file?: { blob: unknown; name: string };
|
||||
/** array of up to 10 embed objects embedded rich content. */
|
||||
embeds?: Embed[];
|
||||
/** allowed mentions for the message */
|
||||
mentions?: {
|
||||
/** An array of allowed mention types to parse from the content. */
|
||||
parse: ("roles" | "users" | "everyone")[];
|
||||
/** Array of role_ids to mention (Max size of 100) */
|
||||
roles?: string[];
|
||||
/** Array of user_ids to mention (Max size of 100) */
|
||||
users?: string[];
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user