import type { ButtonInteraction } from "discord.js"; import type { Option } from "./options"; import { CustomIdTooLong } from "./errors"; export class KittenComponent { type = "component" as const; constructor( public name: string, public config: { options?: Record>; run: (interaction: ButtonInteraction, args: any) => Promise | void; }, ) {} /** * @throws {CustomIdTooLong} if the generated custom ID exceeds Discord's 100 character limit. * @returns a custom ID string that encodes the component name and its options' values. */ id(args: Record = {}): string { const keys = Object.keys(this.config.options || {}); const values = keys.map((key) => encodeURIComponent(String(args[key] ?? ""))); const customId = [this.name, ...values].join(":"); if (customId.length > 100) throw new CustomIdTooLong(this.name, customId.length); return customId; } parseArgs(customId: string): Record { const [, ...parts] = customId.split(":"); const keys = Object.keys(this.config.options || {}); const parsed: Record = {}; keys.forEach((key, index) => { const rawVal = parts[index]; if (rawVal === undefined) return; const val = decodeURIComponent(rawVal); const opt = this.config.options?.[key]; if (opt?.type === "boolean") parsed[key] = val === "true"; else if (opt?.type === "integer" || opt?.type === "number") parsed[key] = Number(val); else parsed[key] = val === "" ? undefined : val; }); return parsed; } }