mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
feat: experimental custom handlers
This commit is contained in:
parent
168aab508a
commit
9b40239b55
@ -4,7 +4,7 @@ import type { Adapter } from '../cache';
|
||||
import { Cache, MemoryAdapter } from '../cache';
|
||||
import type { RegisteredMiddlewares } from '../commands';
|
||||
import type { InferWithPrefix, MiddlewareContext } from '../commands/applications/shared';
|
||||
import { CommandHandler } from '../commands/handler';
|
||||
import { CommandHandler, type CommandHandlerLike } from '../commands/handler';
|
||||
import {
|
||||
ChannelShorter,
|
||||
EmojiShorter,
|
||||
@ -25,8 +25,8 @@ import {
|
||||
} from '../common';
|
||||
|
||||
import type { DeepPartial, IntentStrings, OmitInsert, When } from '../common/types/util';
|
||||
import { ComponentHandler } from '../components/handler';
|
||||
import { LangsHandler } from '../langs/handler';
|
||||
import { ComponentHandler, type ComponentHandlerLike } from '../components/handler';
|
||||
import { LangsHandler, type LangsHandlerLike } from '../langs/handler';
|
||||
import type {
|
||||
ChatInputCommandInteraction,
|
||||
Message,
|
||||
@ -55,9 +55,9 @@ export class BaseClient {
|
||||
name: '[Seyfert]',
|
||||
});
|
||||
|
||||
langs = new LangsHandler(this.logger);
|
||||
commands = new CommandHandler(this.logger, this);
|
||||
components = new ComponentHandler(this.logger, this);
|
||||
langs?: LangsHandlerLike = new LangsHandler(this.logger);
|
||||
commands?: CommandHandlerLike = new CommandHandler(this.logger, this);
|
||||
components?: ComponentHandlerLike = new ComponentHandler(this.logger, this);
|
||||
|
||||
private _applicationId?: string;
|
||||
private _botId?: string;
|
||||
@ -99,7 +99,7 @@ export class BaseClient {
|
||||
return new Router(this.rest).createProxy();
|
||||
}
|
||||
|
||||
setServices({ rest, cache, langs, middlewares }: ServicesOptions) {
|
||||
setServices({ rest, cache, langs, middlewares, handlers }: ServicesOptions) {
|
||||
if (rest) {
|
||||
this.rest = rest;
|
||||
}
|
||||
@ -111,13 +111,24 @@ export class BaseClient {
|
||||
this,
|
||||
);
|
||||
}
|
||||
if (langs) {
|
||||
if (langs.default) this.langs.defaultLang = langs.default;
|
||||
if (langs.aliases) this.langs.aliases = Object.entries(langs.aliases);
|
||||
}
|
||||
if (middlewares) {
|
||||
this.middlewares = middlewares;
|
||||
}
|
||||
if (handlers) {
|
||||
if ('components' in handlers) {
|
||||
this.components = handlers.components;
|
||||
}
|
||||
if ('commands' in handlers) {
|
||||
this.commands = handlers.commands;
|
||||
}
|
||||
if ('langs' in handlers) {
|
||||
this.langs = handlers.langs;
|
||||
}
|
||||
}
|
||||
if (langs) {
|
||||
if (langs.default) this.langs!.defaultLang = langs.default;
|
||||
if (langs.aliases) this.langs!.aliases = Object.entries(langs.aliases);
|
||||
}
|
||||
}
|
||||
|
||||
protected async execute(..._options: unknown[]) {
|
||||
@ -170,7 +181,7 @@ export class BaseClient {
|
||||
applicationId ??= await this.getRC().then(x => x.applicationId ?? this.applicationId);
|
||||
BaseClient.assertString(applicationId, 'applicationId is not a string');
|
||||
|
||||
const commands = this.commands.values.map(x => x.toJSON());
|
||||
const commands = this.commands!.values.map(x => x.toJSON());
|
||||
const filter = filterSplit(commands, command => !command.guild_id);
|
||||
|
||||
await this.proxy.applications(applicationId).commands.put({
|
||||
@ -197,7 +208,7 @@ export class BaseClient {
|
||||
|
||||
async loadCommands(dir?: string) {
|
||||
dir ??= await this.getRC().then(x => x.commands);
|
||||
if (dir) {
|
||||
if (dir && this.commands) {
|
||||
await this.commands.load(dir, this);
|
||||
this.logger.info('CommandHandler loaded');
|
||||
}
|
||||
@ -205,7 +216,7 @@ export class BaseClient {
|
||||
|
||||
async loadComponents(dir?: string) {
|
||||
dir ??= await this.getRC().then(x => x.components);
|
||||
if (dir) {
|
||||
if (dir && this.components) {
|
||||
await this.components.load(dir);
|
||||
this.logger.info('ComponentHandler loaded');
|
||||
}
|
||||
@ -213,14 +224,14 @@ export class BaseClient {
|
||||
|
||||
async loadLangs(dir?: string) {
|
||||
dir ??= await this.getRC().then(x => x.langs);
|
||||
if (dir) {
|
||||
if (dir && this.langs) {
|
||||
await this.langs.load(dir);
|
||||
this.logger.info('LangsHandler loaded');
|
||||
}
|
||||
}
|
||||
|
||||
t(locale: string) {
|
||||
return this.langs.get(locale);
|
||||
return this.langs!.get(locale);
|
||||
}
|
||||
|
||||
async getRC<
|
||||
@ -310,4 +321,9 @@ export interface ServicesOptions {
|
||||
aliases?: Record<string, LocaleString[]>;
|
||||
};
|
||||
middlewares?: Record<string, MiddlewareContext>;
|
||||
handlers?: {
|
||||
components?: ComponentHandlerLike;
|
||||
commands?: CommandHandlerLike;
|
||||
langs?: LangsHandlerLike;
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { parentPort, workerData } from 'node:worker_threads';
|
||||
import type { Command, CommandContext, Message, SubCommand } from '..';
|
||||
import type { Command, CommandContext, EventHandlerLike, Message, SubCommand } from '..';
|
||||
import {
|
||||
GatewayIntentBits,
|
||||
type DeepPartial,
|
||||
@ -22,7 +22,7 @@ import { onMessageCreate } from './onmessagecreate';
|
||||
export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
private __handleGuilds?: Set<string> = new Set();
|
||||
gateway!: ShardManager;
|
||||
events = new EventHandler(this.logger);
|
||||
events?: EventHandlerLike = new EventHandler(this.logger);
|
||||
me!: If<Ready, ClientUser>;
|
||||
declare options: ClientOptions | undefined;
|
||||
memberUpdateHandler = new MemberUpdateHandler();
|
||||
@ -37,6 +37,9 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
...rest
|
||||
}: ServicesOptions & {
|
||||
gateway?: ShardManager;
|
||||
handlers?: ServicesOptions['handlers'] & {
|
||||
events?: EventHandlerLike;
|
||||
};
|
||||
}) {
|
||||
super.setServices(rest);
|
||||
if (gateway) {
|
||||
@ -48,11 +51,14 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
};
|
||||
this.gateway = gateway;
|
||||
}
|
||||
if (rest.handlers && 'events' in rest.handlers) {
|
||||
this.events = rest.handlers.events;
|
||||
}
|
||||
}
|
||||
|
||||
async loadEvents(dir?: string) {
|
||||
dir ??= await this.getRC().then(x => x.events);
|
||||
if (dir) {
|
||||
if (dir && this.events) {
|
||||
await this.events.load(dir);
|
||||
this.logger.info('EventHandler loaded');
|
||||
}
|
||||
@ -114,21 +120,21 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
}
|
||||
|
||||
protected async onPacket(shardId: number, packet: GatewayDispatchPayload) {
|
||||
await this.events.runEvent('RAW', this, packet, shardId);
|
||||
await this.events?.runEvent('RAW', this, packet, shardId);
|
||||
switch (packet.t) {
|
||||
//// Cases where we must obtain the old data before updating
|
||||
case 'GUILD_MEMBER_UPDATE':
|
||||
if (!this.memberUpdateHandler.check(packet.d)) {
|
||||
return;
|
||||
}
|
||||
await this.events.execute(packet.t, packet, this as Client<true>, shardId);
|
||||
await this.events?.execute(packet.t, packet, this as Client<true>, shardId);
|
||||
await this.cache.onPacket(packet);
|
||||
break;
|
||||
case 'PRESENCE_UPDATE':
|
||||
if (!this.presenceUpdateHandler.check(packet.d as any)) {
|
||||
return;
|
||||
}
|
||||
await this.events.execute(packet.t, packet, this as Client<true>, shardId);
|
||||
await this.events?.execute(packet.t, packet, this as Client<true>, shardId);
|
||||
await this.cache.onPacket(packet);
|
||||
break;
|
||||
//rest of the events
|
||||
@ -153,7 +159,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
!((this.gateway.options.intents & GatewayIntentBits.Guilds) === GatewayIntentBits.Guilds)
|
||||
) {
|
||||
if ([...this.gateway.values()].every(shard => shard.data.session_id)) {
|
||||
await this.events.runEvent('BOT_READY', this, this.me, -1);
|
||||
await this.events?.runEvent('BOT_READY', this, this.me, -1);
|
||||
}
|
||||
delete this.__handleGuilds;
|
||||
}
|
||||
@ -163,7 +169,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
if (this.__handleGuilds?.has(packet.d.id)) {
|
||||
this.__handleGuilds.delete(packet.d.id);
|
||||
if (!this.__handleGuilds.size && [...this.gateway.values()].every(shard => shard.data.session_id)) {
|
||||
await this.events.runEvent('BOT_READY', this, this.me, -1);
|
||||
await this.events?.runEvent('BOT_READY', this, this.me, -1);
|
||||
}
|
||||
if (!this.__handleGuilds.size) delete this.__handleGuilds;
|
||||
return;
|
||||
@ -171,7 +177,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
break;
|
||||
}
|
||||
}
|
||||
await this.events.execute(packet.t, packet, this as Client<true>, shardId);
|
||||
await this.events?.execute(packet.t, packet, this as Client<true>, shardId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { ApplicationCommandType, InteractionType, type APIInteraction } from 'discord-api-types/v10';
|
||||
import {
|
||||
CommandContext,
|
||||
type ContextOptionsResolved,
|
||||
MenuCommandContext,
|
||||
OptionResolver,
|
||||
type Command,
|
||||
type ContextMenuCommand,
|
||||
type ContextOptionsResolved,
|
||||
} from '../commands';
|
||||
import type {
|
||||
ChatInputCommandInteraction,
|
||||
@ -28,7 +28,7 @@ export async function onInteractionCreate(
|
||||
switch (body.type) {
|
||||
case InteractionType.ApplicationCommandAutocomplete:
|
||||
{
|
||||
const parentCommand = self.commands.values.find(x => {
|
||||
const parentCommand = self.commands?.values.find(x => {
|
||||
if (x.guild_id && !x.guild_id.includes(body.data.guild_id ?? '')) {
|
||||
return false;
|
||||
}
|
||||
@ -76,7 +76,7 @@ export async function onInteractionCreate(
|
||||
case ApplicationCommandType.Message:
|
||||
case ApplicationCommandType.User:
|
||||
{
|
||||
const command = self.commands.values.find(x => {
|
||||
const command = self.commands?.values.find(x => {
|
||||
if (x.guild_id && !x.guild_id.includes(body.data.guild_id ?? '')) {
|
||||
return false;
|
||||
}
|
||||
@ -135,7 +135,7 @@ export async function onInteractionCreate(
|
||||
case ApplicationCommandType.ChatInput:
|
||||
{
|
||||
const packetData = body.data;
|
||||
const parentCommand = self.commands.values.find(x => {
|
||||
const parentCommand = self.commands?.values.find(x => {
|
||||
if (x.guild_id && !x.guild_id.includes(packetData.guild_id ?? '')) {
|
||||
return false;
|
||||
}
|
||||
@ -206,20 +206,20 @@ export async function onInteractionCreate(
|
||||
case InteractionType.ModalSubmit:
|
||||
{
|
||||
const interaction = BaseInteraction.from(self, body, __reply) as ModalSubmitInteraction;
|
||||
if (self.components.hasModal(interaction)) {
|
||||
if (self.components?.hasModal(interaction)) {
|
||||
await self.components.onModalSubmit(interaction);
|
||||
} else {
|
||||
await self.components.executeModal(interaction);
|
||||
await self.components?.executeModal(interaction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InteractionType.MessageComponent:
|
||||
{
|
||||
const interaction = BaseInteraction.from(self, body, __reply) as ComponentInteraction;
|
||||
if (self.components.hasComponent(body.message.id, interaction.customId)) {
|
||||
if (self.components?.hasComponent(body.message.id, interaction.customId)) {
|
||||
await self.components.onComponent(body.message.id, interaction);
|
||||
} else {
|
||||
await self.components.executeComponent(interaction);
|
||||
await self.components?.executeComponent(interaction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -34,7 +34,7 @@ function getCommandFromContent(
|
||||
const parentName = commandRaw[0];
|
||||
const groupName = commandRaw.length === 3 ? commandRaw[1] : undefined;
|
||||
const subcommandName = groupName ? commandRaw[2] : commandRaw[1];
|
||||
const parent = self.commands.values.find(x => x.name === parentName);
|
||||
const parent = self.commands!.values.find(x => x.name === parentName);
|
||||
const fullCommandName = `${parentName}${
|
||||
groupName ? ` ${groupName} ${subcommandName}` : `${subcommandName ? ` ${subcommandName}` : ''}`
|
||||
}`;
|
||||
@ -48,15 +48,15 @@ function getCommandFromContent(
|
||||
const command =
|
||||
groupName || subcommandName
|
||||
? (parent.options?.find(opt => {
|
||||
if (opt instanceof SubCommand) {
|
||||
if (groupName) {
|
||||
if (opt.group !== groupName) return false;
|
||||
if (opt instanceof SubCommand) {
|
||||
if (groupName) {
|
||||
if (opt.group !== groupName) return false;
|
||||
}
|
||||
if (opt.group && !groupName) return false;
|
||||
return subcommandName === opt.name;
|
||||
}
|
||||
if (opt.group && !groupName) return false;
|
||||
return subcommandName === opt.name;
|
||||
}
|
||||
return false;
|
||||
}) as SubCommand)
|
||||
return false;
|
||||
}) as SubCommand)
|
||||
: parent;
|
||||
|
||||
return {
|
||||
@ -80,7 +80,10 @@ export async function onMessageCreate(
|
||||
|
||||
const content = message.content.slice(prefix.length).trimStart();
|
||||
const { fullCommandName, command, parent } = getCommandFromContent(
|
||||
content.split(' ').filter(x => x).slice(0, 3),
|
||||
content
|
||||
.split(' ')
|
||||
.filter(x => x)
|
||||
.slice(0, 3),
|
||||
self,
|
||||
);
|
||||
|
||||
|
@ -5,7 +5,7 @@ import type { Cache } from '../cache';
|
||||
import { WorkerAdapter } from '../cache';
|
||||
import type { GatewayDispatchPayload, GatewaySendPayload, When } from '../common';
|
||||
import { GatewayIntentBits, LogLevels, Logger, type DeepPartial } from '../common';
|
||||
import { EventHandler } from '../events';
|
||||
import { EventHandler, type EventHandlerLike } from '../events';
|
||||
import { ClientUser } from '../structures';
|
||||
import { Shard, type ShardManagerOptions, type WorkerData } from '../websocket';
|
||||
import type {
|
||||
@ -21,7 +21,7 @@ import type {
|
||||
WorkerStart,
|
||||
} from '../websocket/discord/worker';
|
||||
import type { ManagerMessages } from '../websocket/discord/workermanager';
|
||||
import type { BaseClientOptions, StartOptions } from './base';
|
||||
import type { BaseClientOptions, ServicesOptions, StartOptions } from './base';
|
||||
import { BaseClient } from './base';
|
||||
import type { Client } from './client';
|
||||
import { onInteractionCreate } from './oninteractioncreate';
|
||||
@ -46,7 +46,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
name: `[Worker #${workerData.workerId}]`,
|
||||
});
|
||||
|
||||
events = new EventHandler(this.logger);
|
||||
events?: EventHandlerLike = new EventHandler(this.logger);
|
||||
me!: When<Ready, ClientUser>;
|
||||
promises = new Map<string, { resolve: (value: any) => void; timeout: NodeJS.Timeout }>();
|
||||
|
||||
@ -98,6 +98,19 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
return acc / this.shards.size;
|
||||
}
|
||||
|
||||
setServices({
|
||||
...rest
|
||||
}: ServicesOptions & {
|
||||
handlers?: ServicesOptions['handlers'] & {
|
||||
events?: EventHandlerLike;
|
||||
};
|
||||
}) {
|
||||
super.setServices(rest);
|
||||
if (rest.handlers && 'events' in rest.handlers) {
|
||||
this.events = rest.handlers.events;
|
||||
}
|
||||
}
|
||||
|
||||
async start(options: Omit<DeepPartial<StartOptions>, 'httpConnection' | 'token' | 'connection'> = {}) {
|
||||
await super.start(options);
|
||||
await this.loadEvents(options.eventsDir);
|
||||
@ -106,7 +119,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
|
||||
async loadEvents(dir?: string) {
|
||||
dir ??= await this.getRC().then(x => x.events);
|
||||
if (dir) {
|
||||
if (dir && this.events) {
|
||||
await this.events.load(dir);
|
||||
this.logger.info('EventHandler loaded');
|
||||
}
|
||||
@ -221,7 +234,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
}
|
||||
break;
|
||||
case 'BOT_READY':
|
||||
await this.events.runEvent('BOT_READY', this, this.me, -1);
|
||||
await this.events?.runEvent('BOT_READY', this, this.me, -1);
|
||||
break;
|
||||
case 'API_RESPONSE':
|
||||
{
|
||||
@ -302,14 +315,14 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
}
|
||||
|
||||
protected async onPacket(packet: GatewayDispatchPayload, shardId: number) {
|
||||
await this.events.execute('RAW', packet, this as WorkerClient<true>, shardId);
|
||||
await this.events?.execute('RAW', packet, this as WorkerClient<true>, shardId);
|
||||
switch (packet.t) {
|
||||
case 'GUILD_MEMBER_UPDATE':
|
||||
await this.events.execute(packet.t, packet, this as WorkerClient<true>, shardId);
|
||||
await this.events?.execute(packet.t, packet, this as WorkerClient<true>, shardId);
|
||||
await this.cache.onPacket(packet);
|
||||
break;
|
||||
case 'PRESENCE_UPDATE':
|
||||
await this.events.execute(packet.t, packet, this as WorkerClient<true>, shardId);
|
||||
await this.events?.execute(packet.t, packet, this as WorkerClient<true>, shardId);
|
||||
await this.cache.onPacket(packet);
|
||||
break;
|
||||
//rest of the events
|
||||
@ -332,7 +345,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
type: 'WORKER_READY',
|
||||
workerId: this.workerId,
|
||||
} as WorkerReady);
|
||||
await this.events.runEvent('WORKER_READY', this, this.me, -1);
|
||||
await this.events?.runEvent('WORKER_READY', this, this.me, -1);
|
||||
}
|
||||
delete this.__handleGuilds;
|
||||
}
|
||||
@ -352,14 +365,14 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
type: 'WORKER_READY',
|
||||
workerId: this.workerId,
|
||||
} as WorkerReady);
|
||||
await this.events.runEvent('WORKER_READY', this, this.me, -1);
|
||||
await this.events?.runEvent('WORKER_READY', this, this.me, -1);
|
||||
}
|
||||
if (!this.__handleGuilds.size) delete this.__handleGuilds;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.events.execute(packet.t, packet, this, shardId);
|
||||
await this.events?.execute(packet.t, packet, this, shardId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ export class CommandContext<T extends OptionsRecord = {}, M extends keyof Regist
|
||||
}
|
||||
|
||||
get t() {
|
||||
return this.client.langs.get(this.interaction?.locale ?? this.client.langs.defaultLang ?? 'en-US');
|
||||
return this.client.langs!.get(this.interaction?.locale ?? this.client.langs!.defaultLang ?? 'en-US');
|
||||
}
|
||||
|
||||
get fullCommandName() {
|
||||
|
@ -60,7 +60,7 @@ export class MenuCommandContext<
|
||||
}
|
||||
|
||||
get t() {
|
||||
return this.client.langs.get(this.interaction.locale);
|
||||
return this.client.langs!.get(this.interaction.locale ?? this.client.langs!.defaultLang ?? 'en-US');
|
||||
}
|
||||
|
||||
get fullCommandName() {
|
||||
|
@ -5,6 +5,11 @@ import { Command, SubCommand } from './applications/chat';
|
||||
import { ContextMenuCommand } from './applications/menu';
|
||||
import type { UsingClient } from './applications/shared';
|
||||
|
||||
export interface CommandHandlerLike {
|
||||
values: CommandHandler['values'];
|
||||
load: CommandHandler['load'];
|
||||
}
|
||||
|
||||
export class CommandHandler extends BaseHandler {
|
||||
values: (Command | ContextMenuCommand)[] = [];
|
||||
protected filter = (path: string) => path.endsWith('.js') || (!path.endsWith('.d.ts') && path.endsWith('.ts'));
|
||||
@ -122,20 +127,20 @@ export class CommandHandler extends BaseHandler {
|
||||
if (command.__t) {
|
||||
command.name_localizations = {};
|
||||
command.description_localizations = {};
|
||||
for (const locale of Object.keys(client.langs.values)) {
|
||||
const locales = this.client.langs.aliases.find(x => x[0] === locale)?.[1] ?? [];
|
||||
for (const locale of Object.keys(client.langs!.values)) {
|
||||
const locales = this.client.langs!.aliases.find(x => x[0] === locale)?.[1] ?? [];
|
||||
if (Object.values<string>(Locale).includes(locale)) locales.push(locale as LocaleString);
|
||||
|
||||
if (command.__t.name) {
|
||||
for (const i of locales) {
|
||||
const valueName = client.langs.getKey(locale, command.__t.name!);
|
||||
const valueName = client.langs!.getKey(locale, command.__t.name!);
|
||||
if (valueName) command.name_localizations[i] = valueName;
|
||||
}
|
||||
}
|
||||
|
||||
if (command.__t.description) {
|
||||
for (const i of locales) {
|
||||
const valueKey = client.langs.getKey(locale, command.__t.description!);
|
||||
const valueKey = client.langs!.getKey(locale, command.__t.description!);
|
||||
if (valueKey) command.description_localizations[i] = valueKey;
|
||||
}
|
||||
}
|
||||
@ -146,20 +151,20 @@ export class CommandHandler extends BaseHandler {
|
||||
if (options instanceof SubCommand || !options.locales) continue;
|
||||
options.name_localizations = {};
|
||||
options.description_localizations = {};
|
||||
for (const locale of Object.keys(client.langs.values)) {
|
||||
const locales = this.client.langs.aliases.find(x => x[0] === locale)?.[1] ?? [];
|
||||
for (const locale of Object.keys(client.langs!.values)) {
|
||||
const locales = this.client.langs!.aliases.find(x => x[0] === locale)?.[1] ?? [];
|
||||
if (Object.values<string>(Locale).includes(locale)) locales.push(locale as LocaleString);
|
||||
|
||||
if (options.locales.name) {
|
||||
for (const i of locales) {
|
||||
const valueName = client.langs.getKey(locale, options.locales.name!);
|
||||
const valueName = client.langs!.getKey(locale, options.locales.name!);
|
||||
if (valueName) options.name_localizations[i] = valueName;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.locales.description) {
|
||||
for (const i of locales) {
|
||||
const valueKey = client.langs.getKey(locale, options.locales.description!);
|
||||
const valueKey = client.langs!.getKey(locale, options.locales.description!);
|
||||
if (valueKey) options.description_localizations[i] = valueKey;
|
||||
}
|
||||
}
|
||||
@ -168,8 +173,8 @@ export class CommandHandler extends BaseHandler {
|
||||
|
||||
if (command instanceof Command && command.__tGroups) {
|
||||
command.groups = {};
|
||||
for (const locale of Object.keys(client.langs.values)) {
|
||||
const locales = this.client.langs.aliases.find(x => x[0] === locale)?.[1] ?? [];
|
||||
for (const locale of Object.keys(client.langs!.values)) {
|
||||
const locales = this.client.langs!.aliases.find(x => x[0] === locale)?.[1] ?? [];
|
||||
if (Object.values<string>(Locale).includes(locale)) locales.push(locale as LocaleString);
|
||||
for (const group in command.__tGroups) {
|
||||
command.groups[group] ??= {
|
||||
@ -180,7 +185,7 @@ export class CommandHandler extends BaseHandler {
|
||||
|
||||
if (command.__tGroups[group].name) {
|
||||
for (const i of locales) {
|
||||
const valueName = client.langs.getKey(locale, command.__tGroups[group].name!);
|
||||
const valueName = client.langs!.getKey(locale, command.__tGroups[group].name!);
|
||||
if (valueName) {
|
||||
command.groups[group].name!.push([i, valueName]);
|
||||
}
|
||||
@ -189,7 +194,7 @@ export class CommandHandler extends BaseHandler {
|
||||
|
||||
if (command.__tGroups[group].description) {
|
||||
for (const i of locales) {
|
||||
const valueKey = client.langs.getKey(locale, command.__tGroups[group].description!);
|
||||
const valueKey = client.langs!.getKey(locale, command.__tGroups[group].description!);
|
||||
if (valueKey) {
|
||||
command.groups[group].description!.push([i, valueKey]);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ export class MessageShorter extends BaseShorter {
|
||||
.messages(messageId)
|
||||
.delete({ reason })
|
||||
.then(() => {
|
||||
return this.client.components.onMessageDelete(messageId);
|
||||
return this.client.components?.onMessageDelete(messageId);
|
||||
});
|
||||
}
|
||||
fetch(messageId: string, channelId: string) {
|
||||
|
@ -14,8 +14,28 @@ type COMPONENTS = {
|
||||
__run: (customId: string | string[] | RegExp, callback: ComponentCallback) => any;
|
||||
};
|
||||
|
||||
export interface ComponentHandlerLike {
|
||||
readonly values: Map<string, COMPONENTS>;
|
||||
readonly commands: (ComponentCommand | ModalCommand)[];
|
||||
readonly modals: Map<string, ModalSubmitCallback> | LimitedCollection<string, ModalSubmitCallback>;
|
||||
|
||||
createComponentCollector: ComponentHandler['createComponentCollector'];
|
||||
|
||||
hasModal: ComponentHandler['hasModal'];
|
||||
onModalSubmit: ComponentHandler['onModalSubmit'];
|
||||
executeModal: ComponentHandler['executeModal'];
|
||||
|
||||
hasComponent: ComponentHandler['hasComponent'];
|
||||
executeComponent: ComponentHandler['executeComponent'];
|
||||
onComponent: ComponentHandler['onComponent'];
|
||||
|
||||
load: ComponentHandler['load'];
|
||||
|
||||
onMessageDelete: ComponentHandler['onMessageDelete'];
|
||||
}
|
||||
|
||||
export class ComponentHandler extends BaseHandler {
|
||||
protected onFail?: OnFailCallback;
|
||||
onFail?: OnFailCallback;
|
||||
readonly values = new Map<string, COMPONENTS>();
|
||||
// 10 minutes timeout, because discord dont send an event when the user cancel the modal
|
||||
readonly modals = new LimitedCollection<string, ModalSubmitCallback>({ expire: 60e3 * 10 });
|
||||
@ -99,11 +119,13 @@ export class ComponentHandler extends BaseHandler {
|
||||
}
|
||||
|
||||
hasComponent(id: string, customId: string) {
|
||||
return this.values.get(id)?.components?.some(x => {
|
||||
if (typeof x.match === 'string') return x.match === customId;
|
||||
if (Array.isArray(x.match)) return x.match.includes(customId);
|
||||
return customId.match(x.match);
|
||||
});
|
||||
return (
|
||||
this.values.get(id)?.components?.some(x => {
|
||||
if (typeof x.match === 'string') return x.match === customId;
|
||||
if (Array.isArray(x.match)) return x.match.includes(customId);
|
||||
return customId.match(x.match);
|
||||
}) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
resetTimeouts(id: string) {
|
||||
@ -164,6 +186,7 @@ export class ComponentHandler extends BaseHandler {
|
||||
}
|
||||
|
||||
async reload(path: string) {
|
||||
if (!this.client.components) return;
|
||||
const component = this.client.components.commands.find(
|
||||
x =>
|
||||
x.__filePath?.endsWith(`${path}.js`) ||
|
||||
@ -184,6 +207,7 @@ export class ComponentHandler extends BaseHandler {
|
||||
}
|
||||
|
||||
async reloadAll() {
|
||||
if (!this.client.components) return;
|
||||
for (const i of this.client.components.commands) {
|
||||
if (!i.__filePath) return this.logger.warn('Unknown command dont have __filePath property', i);
|
||||
await this.reload(i.__filePath);
|
||||
|
@ -19,6 +19,13 @@ type EventValue = MakeRequired<ClientEvent, '__filePath'> & { fired?: boolean };
|
||||
|
||||
type GatewayEvents = Uppercase<SnakeCase<keyof ClientEvents>>;
|
||||
|
||||
export interface EventHandlerLike {
|
||||
runEvent: EventHandler['runEvent'];
|
||||
execute: EventHandler['execute'];
|
||||
load: EventHandler['load'];
|
||||
values: EventHandler['values'];
|
||||
}
|
||||
|
||||
export class EventHandler extends BaseHandler {
|
||||
protected onFail: OnFailCallback = err => this.logger.warn('<Client>.events.OnFail', err);
|
||||
protected filter = (path: string) => path.endsWith('.js') || (!path.endsWith('.d.ts') && path.endsWith('.ts'));
|
||||
@ -54,7 +61,7 @@ export class EventHandler extends BaseHandler {
|
||||
case 'MESSAGE_CREATE':
|
||||
{
|
||||
const { d: data } = args[0] as GatewayMessageCreateDispatch;
|
||||
if (args[1].components.values.has(data.interaction?.id ?? data.id)) {
|
||||
if (args[1].components?.values.has(data.interaction?.id ?? data.id)) {
|
||||
args[1].components.values.get(data.interaction?.id ?? data.id)!.messageId = data.id;
|
||||
}
|
||||
}
|
||||
@ -62,20 +69,20 @@ export class EventHandler extends BaseHandler {
|
||||
case 'MESSAGE_DELETE':
|
||||
{
|
||||
const { d: data } = args[0] as GatewayMessageDeleteDispatch;
|
||||
const value = [...args[1].components.values].find(x => x[1].messageId === data.id);
|
||||
const value = [...(args[1].components?.values ?? [])].find(x => x[1].messageId === data.id);
|
||||
if (value) {
|
||||
args[1].components.onMessageDelete(value[0]);
|
||||
args[1].components!.onMessageDelete(value[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'MESSAGE_DELETE_BULK':
|
||||
{
|
||||
const { d: data } = args[0] as GatewayMessageDeleteBulkDispatch;
|
||||
const values = [...args[1].components.values];
|
||||
const values = [...(args[1].components?.values ?? [])];
|
||||
data.ids.forEach(id => {
|
||||
const value = values.find(x => x[1].messageId === id);
|
||||
if (value) {
|
||||
args[1].components.onMessageDelete(value[0]);
|
||||
args[1].components!.onMessageDelete(value[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,15 @@
|
||||
import { BaseHandler, type Locale, type LocaleString } from '../common';
|
||||
import { LangRouter } from './router';
|
||||
|
||||
export interface LangsHandlerLike {
|
||||
getKey: LangsHandler['getKey'];
|
||||
load: LangsHandler['load'];
|
||||
values: LangsHandler['values'];
|
||||
aliases: LangsHandler['aliases'];
|
||||
get: LangsHandler['get'];
|
||||
defaultLang?: LangsHandler['defaultLang'];
|
||||
}
|
||||
|
||||
export class LangsHandler extends BaseHandler {
|
||||
values: Partial<Record<string, any>> = {};
|
||||
protected filter = (path: string) =>
|
||||
|
@ -388,7 +388,7 @@ export class Interaction<
|
||||
.webhooks(this.applicationId)(this.token)
|
||||
.messages(messageId)
|
||||
.delete()
|
||||
.then(() => this.client.components.onMessageDelete(messageId === '@original' ? this.id : messageId));
|
||||
.then(() => this.client.components?.onMessageDelete(messageId === '@original' ? this.id : messageId));
|
||||
}
|
||||
|
||||
async createResponse({ files, ...body }: MessageWebhookCreateBodyRequest) {
|
||||
|
@ -51,7 +51,7 @@ export class BaseMessage extends DiscordBase {
|
||||
}
|
||||
|
||||
createComponentCollector(options?: ListenerOptions) {
|
||||
return this.client.components.createComponentCollector(this.id, options);
|
||||
return this.client.components!.createComponentCollector(this.id, options);
|
||||
}
|
||||
|
||||
get url() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user