mirror of
https://github.com/discordeno/discordeno.git
synced 2026-09-17 08:47:22 +00:00
more fixes for limits
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import type { ButtonComponent } from "../../types/messages/components/button_component.ts";
|
||||
import type { ActionRoleComponents } from "../../types/messages/components/message_components.ts";
|
||||
import { MessageComponentTypes } from "../../types/messages/components/message_component_types.ts";
|
||||
|
||||
/** A type guard function to tell if it is a button component */
|
||||
export function isButton(component: ActionRoleComponents): component is ButtonComponent {
|
||||
return Reflect.has(component, "type");
|
||||
return component.type === MessageComponentTypes.Button;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { ActionRoleComponents } from "../../types/messages/components/message_components.ts";
|
||||
import { SelectMenuComponent } from "../../types/messages/components/select_menu.ts";
|
||||
import { MessageComponentTypes } from "../../types/messages/components/message_component_types.ts";
|
||||
import type { SelectMenuComponent } from "../../types/messages/components/select_menu.ts";
|
||||
|
||||
/** A type guard function to tell if it is a button component */
|
||||
export function isSelectMenu(component: ActionRoleComponents): component is SelectMenuComponent {
|
||||
return !Reflect.has(component, "type");
|
||||
return component.type === MessageComponentTypes.SelectMenu;
|
||||
}
|
||||
|
||||
@@ -98,4 +98,14 @@ export enum Errors {
|
||||
COMPONENT_LABEL_TOO_BIG = "COMPONENT_LABEL_TOO_BIG",
|
||||
COMPONENT_CUSTOM_ID_TOO_BIG = "COMPONENT_CUSTOM_ID_TOO_BIG",
|
||||
BUTTON_REQUIRES_CUSTOM_ID = "BUTTON_REQUIRES_CUSTOM_ID",
|
||||
COMPONENT_SELECT_MUST_BE_ALONE = "COMPONENT_SELECT_MUST_BE_ALONE",
|
||||
COMPONENT_PLACEHOLDER_TOO_BIG = "COMPONENT_PLACEHOLDER_TOO_BIG",
|
||||
COMPONENT_SELECT_MINVALUE_TOO_LOW = "COMPONENT_SELECT_MINVALUE_TOO_LOW",
|
||||
COMPONENT_SELECT_MINVALUE_TOO_MANY = "COMPONENT_SELECT_MINVALUE_TOO_MANY",
|
||||
COMPONENT_SELECT_MAXVALUE_TOO_LOW = "COMPONENT_SELECT_MAXVALUE_TOO_LOW",
|
||||
COMPONENT_SELECT_MAXVALUE_TOO_MANY = "COMPONENT_SELECT_MAXVALUE_TOO_MANY",
|
||||
COMPONENT_SELECT_OPTIONS_TOO_LOW = "COMPONENT_SELECT_OPTIONS_TOO_LOW",
|
||||
COMPONENT_SELECT_OPTIONS_TOO_MANY = "COMPONENT_SELECT_OPTIONS_TOO_MANY",
|
||||
SELECT_OPTION_LABEL_TOO_BIG = "SELECT_OPTION_LABEL_TOO_BIG",
|
||||
SELECT_OPTION_VALUE_TOO_BIG = "SELECT_OPTION_VALUE_TOO_BIG",
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { SelectMenuData } from "../messages/components/select_data.ts";
|
||||
import { ButtonData } from "../messages/components/button_data.ts";
|
||||
|
||||
/** https://discord.com/developers/docs/interactions/slash-commands#interaction */
|
||||
export interface Interaction {
|
||||
export interface Interaction extends BaseInteraction {
|
||||
/** The command data payload */
|
||||
data?: ApplicationCommandInteractionData | ButtonData | SelectMenuData;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SelectOption } from "./select_option.ts";
|
||||
|
||||
export interface SelectMenuComponent {
|
||||
type: 3;
|
||||
/** A custom identifier for this component. Maximum 100 characters. */
|
||||
customId: string;
|
||||
/** A custom placeholder text if nothing is selected. Maximum 100 characters. */
|
||||
|
||||
+84
-14
@@ -13,6 +13,7 @@ import type { DiscordImageFormat } from "../types/misc/image_format.ts";
|
||||
import type { DiscordImageSize } from "../types/misc/image_size.ts";
|
||||
import { SLASH_COMMANDS_NAME_REGEX } from "./constants.ts";
|
||||
import { validateLength } from "./validate_length.ts";
|
||||
import { isSelectMenu } from "../helpers/type_guards/is_select_menu.ts";
|
||||
|
||||
export async function urlToBase64(url: string) {
|
||||
const buffer = await fetch(url).then((res) => res.arrayBuffer());
|
||||
@@ -221,9 +222,18 @@ export function validateComponents(components: MessageComponents) {
|
||||
// Max of 5 Buttons (or any component type) within an ActionRow
|
||||
if (component.components?.length > 5) {
|
||||
throw new Error(Errors.TOO_MANY_COMPONENTS);
|
||||
} else if (
|
||||
component.components?.length > 1 &&
|
||||
component.components.some((subcomponent) => isSelectMenu(subcomponent))
|
||||
) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_MUST_BE_ALONE);
|
||||
}
|
||||
|
||||
for (const subcomponent of component.components) {
|
||||
if (subcomponent.customId && !validateLength(subcomponent.customId, { max: 100 })) {
|
||||
throw new Error(Errors.COMPONENT_CUSTOM_ID_TOO_BIG);
|
||||
}
|
||||
|
||||
// 5 Link buttons can not have a customId
|
||||
if (isButton(subcomponent)) {
|
||||
if (subcomponent.type === ButtonStyles.Link && subcomponent.customId) {
|
||||
@@ -235,27 +245,87 @@ export function validateComponents(components: MessageComponents) {
|
||||
}
|
||||
|
||||
if (!validateLength(subcomponent.label, { max: 80 })) {
|
||||
throw new Error(Errors.subcomponent_LABEL_TOO_BIG);
|
||||
throw new Error(Errors.COMPONENT_LABEL_TOO_BIG);
|
||||
}
|
||||
|
||||
if (subcomponent.customId && !validateLength(subcomponent.customId, { max: 100 })) {
|
||||
throw new Error(Errors.subcomponent_CUSTOM_ID_TOO_BIG);
|
||||
subcomponent.emoji = makeEmojiFromString(subcomponent.emoji);
|
||||
}
|
||||
|
||||
if (typeof subcomponent.emoji === "string") {
|
||||
// A snowflake id was provided
|
||||
if (/^[0-9]+$/.test(subcomponent.emoji)) {
|
||||
subcomponent.emoji = {
|
||||
id: subcomponent.emoji,
|
||||
};
|
||||
} else {
|
||||
// A unicode emoji was provided
|
||||
subcomponent.emoji = {
|
||||
name: subcomponent.emoji,
|
||||
};
|
||||
if (isSelectMenu(subcomponent)) {
|
||||
if (subcomponent.placeholder && !validateLength(subcomponent.placeholder, { max: 100 })) {
|
||||
throw new Error(Errors.COMPONENT_PLACEHOLDER_TOO_BIG);
|
||||
}
|
||||
|
||||
if (subcomponent.minValues) {
|
||||
if (subcomponent.minValues < 1) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_MINVALUE_TOO_LOW);
|
||||
}
|
||||
|
||||
if (subcomponent.minValues > 25) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_MINVALUE_TOO_MANY);
|
||||
}
|
||||
}
|
||||
|
||||
if (subcomponent.maxValues) {
|
||||
if (subcomponent.maxValues < 1) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_MAXVALUE_TOO_LOW);
|
||||
}
|
||||
|
||||
if (subcomponent.maxValues > 25) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_MAXVALUE_TOO_MANY);
|
||||
}
|
||||
}
|
||||
|
||||
if (subcomponent.options.length < 1) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_OPTIONS_TOO_LOW);
|
||||
}
|
||||
|
||||
if (subcomponent.options.length > 25) {
|
||||
throw new Error(Errors.COMPONENT_SELECT_OPTIONS_TOO_MANY);
|
||||
}
|
||||
|
||||
for (const option of subcomponent.options) {
|
||||
if (!validateLength(option.label, { max: 25 })) {
|
||||
throw new Error(Errors.SELECT_OPTION_LABEL_TOO_BIG);
|
||||
}
|
||||
|
||||
if (!validateLength(option.value, { max: 100 })) {
|
||||
throw new Error(Errors.SELECT_OPTION_VALUE_TOO_BIG);
|
||||
}
|
||||
|
||||
if (option.description && !validateLength(option.description, { max: 50 })) {
|
||||
throw new Error(Errors.SELECT_OPTION_VALUE_TOO_BIG);
|
||||
}
|
||||
|
||||
option.emoji = makeEmojiFromString(option.emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeEmojiFromString(
|
||||
emoji?:
|
||||
| string
|
||||
| {
|
||||
id?: string | undefined;
|
||||
name?: string | undefined;
|
||||
animated?: boolean | undefined;
|
||||
}
|
||||
) {
|
||||
if (typeof emoji !== "string") return emoji;
|
||||
|
||||
// A snowflake id was provided
|
||||
if (/^[0-9]+$/.test(emoji)) {
|
||||
emoji = {
|
||||
id: emoji,
|
||||
};
|
||||
} else {
|
||||
// A unicode emoji was provided
|
||||
emoji = {
|
||||
name: emoji,
|
||||
};
|
||||
}
|
||||
|
||||
return emoji;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user