more fixes for limits

This commit is contained in:
Skillz
2021-05-28 09:20:30 -04:00
parent a293cd27d3
commit 1e61943e73
6 changed files with 101 additions and 18 deletions
+2 -1
View File
@@ -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;
}
+3 -2
View File
@@ -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;
}
+10
View File
@@ -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",
}
+1 -1
View File
@@ -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
View File
@@ -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;
}