diff --git a/packages/builders/src/Assertions.ts b/packages/builders/src/Assertions.ts index c672c95c08dc..54d87c0718e1 100644 --- a/packages/builders/src/Assertions.ts +++ b/packages/builders/src/Assertions.ts @@ -3,6 +3,7 @@ import { z } from 'zod'; export const idPredicate = z.int().min(0).max(2_147_483_647).optional(); export const customIdPredicate = z.string().min(1).max(100); +export const snowflakePredicate = z.string().regex(/^\d{17,20}$/); export const memberPermissionsPredicate = z.coerce.bigint(); diff --git a/packages/builders/src/components/Assertions.ts b/packages/builders/src/components/Assertions.ts index 67b9b44fc0c4..57a164fde659 100644 --- a/packages/builders/src/components/Assertions.ts +++ b/packages/builders/src/components/Assertions.ts @@ -1,12 +1,12 @@ import { ButtonStyle, ChannelType, ComponentType, SelectMenuDefaultValueType } from 'discord-api-types/v10'; import { z } from 'zod'; -import { idPredicate, customIdPredicate } from '../Assertions.js'; +import { customIdPredicate, idPredicate, snowflakePredicate } from '../Assertions.js'; const labelPredicate = z.string().min(1).max(80); export const emojiPredicate = z .strictObject({ - id: z.string().optional(), + id: snowflakePredicate.optional(), name: z.string().min(2).max(32).optional(), animated: z.boolean().optional(), }) @@ -39,7 +39,7 @@ const buttonLinkPredicate = buttonPredicateBase.extend({ const buttonPremiumPredicate = buttonPredicateBase.extend({ style: z.literal(ButtonStyle.Premium), - sku_id: z.string(), + sku_id: snowflakePredicate, }); export const buttonPredicate = z.discriminatedUnion('style', [ @@ -51,7 +51,7 @@ export const buttonPredicate = z.discriminatedUnion('style', [ buttonPremiumPredicate, ]); -const selectMenuBasePredicate = z.object({ +const selectMenuBasePredicate = z.strictObject({ id: idPredicate, placeholder: z.string().max(150).optional(), min_values: z.number().min(0).max(25).optional(), @@ -64,7 +64,7 @@ export const selectMenuChannelPredicate = selectMenuBasePredicate.extend({ type: z.literal(ComponentType.ChannelSelect), channel_types: z.enum(ChannelType).array().optional(), default_values: z - .object({ id: z.string(), type: z.literal(SelectMenuDefaultValueType.Channel) }) + .strictObject({ id: snowflakePredicate, type: z.literal(SelectMenuDefaultValueType.Channel) }) .array() .max(25) .optional(), @@ -73,8 +73,8 @@ export const selectMenuChannelPredicate = selectMenuBasePredicate.extend({ export const selectMenuMentionablePredicate = selectMenuBasePredicate.extend({ type: z.literal(ComponentType.MentionableSelect), default_values: z - .object({ - id: z.string(), + .strictObject({ + id: snowflakePredicate, type: z.literal([SelectMenuDefaultValueType.Role, SelectMenuDefaultValueType.User]), }) .array() @@ -85,13 +85,13 @@ export const selectMenuMentionablePredicate = selectMenuBasePredicate.extend({ export const selectMenuRolePredicate = selectMenuBasePredicate.extend({ type: z.literal(ComponentType.RoleSelect), default_values: z - .object({ id: z.string(), type: z.literal(SelectMenuDefaultValueType.Role) }) + .strictObject({ id: snowflakePredicate, type: z.literal(SelectMenuDefaultValueType.Role) }) .array() .max(25) .optional(), }); -export const selectMenuStringOptionPredicate = z.object({ +export const selectMenuStringOptionPredicate = z.strictObject({ label: labelPredicate, value: z.string().min(1).max(100), description: z.string().min(1).max(100).optional(), @@ -104,37 +104,23 @@ export const selectMenuStringPredicate = selectMenuBasePredicate type: z.literal(ComponentType.StringSelect), options: selectMenuStringOptionPredicate.array().min(1).max(25), }) - .check((ctx) => { - const addIssue = (name: string, minimum: number) => - ctx.issues.push({ - code: 'too_small', - message: `The number of options must be greater than or equal to ${name}`, + .superRefine((value, ctx) => { + if (value.min_values !== undefined && value.options.length < value.min_values) { + ctx.addIssue({ + code: z.ZodIssueCode.too_small, + minimum: value.min_values, + type: 'array', inclusive: true, - minimum, - type: 'number', path: ['options'], - origin: 'number', - input: minimum, + message: `The number of options must be greater than or equal to min_values`, }); - - if (ctx.value.min_values !== undefined && ctx.value.options.length < ctx.value.min_values) { - addIssue('min_values', ctx.value.min_values); } - if ( - ctx.value.min_values !== undefined && - ctx.value.max_values !== undefined && - ctx.value.min_values > ctx.value.max_values - ) { - ctx.issues.push({ - code: 'too_big', - message: `The maximum amount of options must be greater than or equal to the minimum amount of options`, - inclusive: true, - maximum: ctx.value.max_values, - type: 'number', + if (value.min_values !== undefined && value.max_values !== undefined && value.min_values > value.max_values) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, path: ['min_values'], - origin: 'number', - input: ctx.value.min_values, + message: `The maximum amount of options must be greater than or equal to the minimum amount of options`, }); } }); @@ -142,23 +128,23 @@ export const selectMenuStringPredicate = selectMenuBasePredicate export const selectMenuUserPredicate = selectMenuBasePredicate.extend({ type: z.literal(ComponentType.UserSelect), default_values: z - .object({ id: z.string(), type: z.literal(SelectMenuDefaultValueType.User) }) + .strictObject({ id: snowflakePredicate, type: z.literal(SelectMenuDefaultValueType.User) }) .array() .max(25) .optional(), }); -export const actionRowPredicate = z.object({ +export const actionRowPredicate = z.strictObject({ id: idPredicate, type: z.literal(ComponentType.ActionRow), components: z.union([ z - .object({ type: z.literal(ComponentType.Button) }) + .strictObject({ type: z.literal(ComponentType.Button) }) .array() .min(1) .max(5), z - .object({ + .strictObject({ type: z.literal([ ComponentType.ChannelSelect, ComponentType.MentionableSelect,