pkgs/core/src/components.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
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<string, Option<any, any>>;
run: (interaction: ButtonInteraction, args: any) => Promise<void> | 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, any> = {}): 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<string, any> {
const [, ...parts] = customId.split(":");
const keys = Object.keys(this.config.options || {});
const parsed: Record<string, any> = {};
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;
}
}
|