mirror of
https://github.com/arthur-pbty/flint.git
synced 2026-08-01 20:29:03 +02:00
mise au bonne endroit des type
This commit is contained in:
@@ -11,7 +11,7 @@ import { EmbedBuilder } from "discord.js";
|
|||||||
|
|
||||||
import { buildPrefixUsage, buildSlashUsage, resolvePrefixTrigger, resolveSlashName } from "../framework/commands/usage.js";
|
import { buildPrefixUsage, buildSlashUsage, resolvePrefixTrigger, resolveSlashName } from "../framework/commands/usage.js";
|
||||||
import { defineCommand } from "../framework/commands/defineCommand.js";
|
import { defineCommand } from "../framework/commands/defineCommand.js";
|
||||||
import type { BotCommand, CommandExecutionContext } from "../framework/types/command.js";
|
import type { BotCommand, CommandExecutionContext } from "../types/command.js";
|
||||||
|
|
||||||
const categoryName = (command: BotCommand): string => command.meta.category;
|
const categoryName = (command: BotCommand): string => command.meta.category;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { presenceCommand } from "./presence.js";
|
|||||||
import { pingCommand } from "./ping.js";
|
import { pingCommand } from "./ping.js";
|
||||||
import { welcomeCommand } from "./welcome.js";
|
import { welcomeCommand } from "./welcome.js";
|
||||||
|
|
||||||
import type { BotCommand } from "../framework/types/command.js";
|
import type { BotCommand } from "../types/command.js";
|
||||||
|
|
||||||
/** CommandList: tableau ordonné des commandes disponibles. */
|
/** CommandList: tableau ordonné des commandes disponibles. */
|
||||||
export const commandList: BotCommand[] = [
|
export const commandList: BotCommand[] = [
|
||||||
|
|||||||
@@ -29,32 +29,19 @@ import { getMemberMessageStore } from "../framework/memberMessages/memberMessage
|
|||||||
import {
|
import {
|
||||||
MEMBER_MESSAGE_RENDER_TYPES,
|
MEMBER_MESSAGE_RENDER_TYPES,
|
||||||
isMemberMessageRenderTypeValue,
|
isMemberMessageRenderTypeValue,
|
||||||
type MemberMessageConfig,
|
|
||||||
type MemberMessageKind,
|
|
||||||
type MemberMessageRenderType,
|
|
||||||
} from "../framework/memberMessages/memberMessageTypes.js";
|
} from "../framework/memberMessages/memberMessageTypes.js";
|
||||||
import type { CommandExecutionContext } from "../framework/types/command.js";
|
import type { CommandExecutionContext } from "../types/command.js";
|
||||||
|
import type {
|
||||||
|
MemberMessageConfig,
|
||||||
|
MemberMessageCustomIds,
|
||||||
|
MemberMessageKind,
|
||||||
|
MemberMessagePanelSession,
|
||||||
|
MemberMessagePanelUiState,
|
||||||
|
MemberMessageRenderType,
|
||||||
|
} from "../types/memberMessages.js";
|
||||||
|
|
||||||
const memberMessageI18n = new I18nService(env.DEFAULT_LANG);
|
const memberMessageI18n = new I18nService(env.DEFAULT_LANG);
|
||||||
|
|
||||||
interface MemberMessageCustomIds {
|
|
||||||
toggleButton: string;
|
|
||||||
channelButton: string;
|
|
||||||
channelCancelButton: string;
|
|
||||||
typeSelect: string;
|
|
||||||
channelSelect: string;
|
|
||||||
testButton: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MemberMessagePanelUiState {
|
|
||||||
channelPickerOpen: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MemberMessagePanelSession {
|
|
||||||
collector: ReturnType<Message["createMessageComponentCollector"]>;
|
|
||||||
disable: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activePanelsByUser = new Map<string, MemberMessagePanelSession>();
|
const activePanelsByUser = new Map<string, MemberMessagePanelSession>();
|
||||||
|
|
||||||
const panelSessionKey = (kind: MemberMessageKind, guildId: string, userId: string): string => {
|
const panelSessionKey = (kind: MemberMessageKind, guildId: string, userId: string): string => {
|
||||||
|
|||||||
+10
-29
@@ -23,6 +23,15 @@ import {
|
|||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
import { defineCommand } from "../framework/commands/defineCommand.js";
|
import { defineCommand } from "../framework/commands/defineCommand.js";
|
||||||
import { env } from "../framework/config/env.js";
|
import { env } from "../framework/config/env.js";
|
||||||
|
import type {
|
||||||
|
DiscordPresenceStatus,
|
||||||
|
PresenceActivityTypeValue,
|
||||||
|
PresenceCustomIds,
|
||||||
|
PresencePanelSession,
|
||||||
|
PresenceRuntimeState,
|
||||||
|
PresenceState,
|
||||||
|
PresenceStatusValue,
|
||||||
|
} from "../types/presence.js";
|
||||||
import { getPresenceStore } from "../framework/presence/presenceStore.js";
|
import { getPresenceStore } from "../framework/presence/presenceStore.js";
|
||||||
import {
|
import {
|
||||||
PRESENCE_TEMPLATE_REFRESH_INTERVAL_MS,
|
PRESENCE_TEMPLATE_REFRESH_INTERVAL_MS,
|
||||||
@@ -42,34 +51,8 @@ import {
|
|||||||
sanitizeActivityText,
|
sanitizeActivityText,
|
||||||
sanitizeActivityTexts,
|
sanitizeActivityTexts,
|
||||||
sanitizePresenceRotationIntervalSeconds,
|
sanitizePresenceRotationIntervalSeconds,
|
||||||
type PresenceActivityTypeValue,
|
|
||||||
type PresenceState,
|
|
||||||
type PresenceStatusValue,
|
|
||||||
} from "../framework/presence/presenceTypes.js";
|
} from "../framework/presence/presenceTypes.js";
|
||||||
import type { CommandExecutionContext } from "../framework/types/command.js";
|
import type { CommandExecutionContext } from "../types/command.js";
|
||||||
|
|
||||||
interface PresenceCustomIds {
|
|
||||||
statusSelect: string;
|
|
||||||
activitySelect: string;
|
|
||||||
textButton: string;
|
|
||||||
intervalButton: string;
|
|
||||||
textModal: string;
|
|
||||||
textInput: string;
|
|
||||||
intervalModal: string;
|
|
||||||
intervalInput: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PresencePanelSession {
|
|
||||||
collector: ReturnType<Message["createMessageComponentCollector"]>;
|
|
||||||
disable: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PresenceRuntimeState {
|
|
||||||
dynamicPresenceRefreshTimer: NodeJS.Timeout | null;
|
|
||||||
presenceRotationTimer: NodeJS.Timeout | null;
|
|
||||||
activePresenceTextIndex: number;
|
|
||||||
activePanelsByUserId: Map<string, PresencePanelSession>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const presenceRuntimeByBotId = new Map<string, PresenceRuntimeState>();
|
const presenceRuntimeByBotId = new Map<string, PresenceRuntimeState>();
|
||||||
|
|
||||||
@@ -129,8 +112,6 @@ const DISCORD_ACTIVITY_TYPES: Record<PresenceActivityTypeValue, ActivityType> =
|
|||||||
CUSTOM: ActivityType.Custom,
|
CUSTOM: ActivityType.Custom,
|
||||||
};
|
};
|
||||||
|
|
||||||
type DiscordPresenceStatus = "online" | "idle" | "dnd" | "invisible";
|
|
||||||
|
|
||||||
const resolveDiscordStatus = (status: PresenceStatusValue): DiscordPresenceStatus =>
|
const resolveDiscordStatus = (status: PresenceStatusValue): DiscordPresenceStatus =>
|
||||||
status === "streaming" ? "online" : status;
|
status === "streaming" ? "online" : status;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
import type { ChatInputCommandInteraction, GuildBasedChannel, Message } from "discord.js";
|
import type { ChatInputCommandInteraction, GuildBasedChannel, Message } from "discord.js";
|
||||||
|
|
||||||
import type { CommandArgValue, CommandArgument, TranslationVars } from "../types/command.js";
|
import type { ArgumentParseError, ParsedArgumentsResult } from "../../types/argParser.js";
|
||||||
|
import type { CommandArgValue, CommandArgument } from "../../types/command.js";
|
||||||
export interface ArgumentParseError {
|
|
||||||
key: string;
|
|
||||||
vars?: TranslationVars;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedArgumentsResult {
|
|
||||||
values: Record<string, CommandArgValue>;
|
|
||||||
errors: ArgumentParseError[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const USER_MENTION_PATTERN = /^<@!?(\d{16,22})>$/;
|
const USER_MENTION_PATTERN = /^<@!?(\d{16,22})>$/;
|
||||||
const CHANNEL_MENTION_PATTERN = /^<#(\d{16,22})>$/;
|
const CHANNEL_MENTION_PATTERN = /^<#(\d{16,22})>$/;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { BotCommand, BotCommandInput } from "../types/command.js";
|
import type { BotCommand, BotCommandInput } from "../../types/command.js";
|
||||||
|
|
||||||
const assertRequiredArgsBeforeOptional = (input: BotCommandInput): void => {
|
const assertRequiredArgsBeforeOptional = (input: BotCommandInput): void => {
|
||||||
const args = input.args ?? [];
|
const args = input.args ?? [];
|
||||||
|
|||||||
@@ -1,21 +1,7 @@
|
|||||||
import { REST, Routes } from "discord.js";
|
import { REST, Routes } from "discord.js";
|
||||||
|
|
||||||
import { buildSlashPayload } from "./slashBuilder.js";
|
import { buildSlashPayload } from "./slashBuilder.js";
|
||||||
import type { CommandRegistry } from "./registry.js";
|
import type { DeployCommandsOptions, DeployCommandsResult } from "../../types/deploy.js";
|
||||||
import type { I18nService } from "../../i18n/index.js";
|
|
||||||
|
|
||||||
export interface DeployCommandsOptions {
|
|
||||||
token: string;
|
|
||||||
clientId: string;
|
|
||||||
guildId?: string;
|
|
||||||
registry: CommandRegistry;
|
|
||||||
i18n: I18nService;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeployCommandsResult {
|
|
||||||
scope: "guild" | "global";
|
|
||||||
count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deployApplicationCommands = async (options: DeployCommandsOptions): Promise<DeployCommandsResult> => {
|
export const deployApplicationCommands = async (options: DeployCommandsOptions): Promise<DeployCommandsResult> => {
|
||||||
const body = buildSlashPayload(options.registry.getAll(), options.i18n);
|
const body = buildSlashPayload(options.registry.getAll(), options.i18n);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { BotCommand, PrefixTriggerMatch } from "../types/command.js";
|
import type { BotCommand, PrefixTriggerMatch } from "../../types/command.js";
|
||||||
import { SUPPORTED_LANGS } from "../types/command.js";
|
import { SUPPORTED_LANGS } from "../../types/command.js";
|
||||||
import type { I18nService } from "../../i18n/index.js";
|
import type { I18nService } from "../../i18n/index.js";
|
||||||
|
|
||||||
const normalize = (value: string): string => value.trim().toLowerCase();
|
const normalize = (value: string): string => value.trim().toLowerCase();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
type RESTPostAPIChatInputApplicationCommandsJSONBody,
|
type RESTPostAPIChatInputApplicationCommandsJSONBody,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
import type { BotCommand, CommandArgument, SupportedLang } from "../types/command.js";
|
import type { BotCommand, CommandArgument, SupportedLang } from "../../types/command.js";
|
||||||
import type { I18nService } from "../../i18n/index.js";
|
import type { I18nService } from "../../i18n/index.js";
|
||||||
|
|
||||||
const LANG_TO_DISCORD_LOCALE: Record<SupportedLang, string> = {
|
const LANG_TO_DISCORD_LOCALE: Record<SupportedLang, string> = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { BotCommand, CommandI18nTools, SupportedLang } from "../types/command.js";
|
import type { BotCommand, CommandI18nTools, SupportedLang } from "../../types/command.js";
|
||||||
|
|
||||||
const formatArgToken = (name: string, required: boolean): string => required ? `<${name}>` : `[${name}]`;
|
const formatArgToken = (name: string, required: boolean): string => required ? `<${name}>` : `[${name}]`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { config as loadEnv } from "dotenv";
|
import { config as loadEnv } from "dotenv";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { SUPPORTED_LANGS } from "../types/command.js";
|
import { SUPPORTED_LANGS } from "../../types/command.js";
|
||||||
|
|
||||||
loadEnv();
|
loadEnv();
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
type PermissionResolvable,
|
type PermissionResolvable,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
import type { BotCommand, CommandExecutionContext } from "../types/command.js";
|
import type { BotCommand, CommandExecutionContext } from "../../types/command.js";
|
||||||
|
|
||||||
const COOLDOWN_SWEEP_INTERVAL_MS = 60_000;
|
const COOLDOWN_SWEEP_INTERVAL_MS = 60_000;
|
||||||
const COOLDOWN_SWEEP_MIN_ENTRIES = 512;
|
const COOLDOWN_SWEEP_MIN_ENTRIES = 512;
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
import { createCanvas, loadImage, type SKRSContext2D } from "@napi-rs/canvas";
|
import { createCanvas, loadImage, type SKRSContext2D } from "@napi-rs/canvas";
|
||||||
|
|
||||||
import type { MemberMessageKind } from "./memberMessageTypes.js";
|
import type { MemberMessageImageInput } from "../../types/memberMessages.js";
|
||||||
|
|
||||||
interface MemberMessageImageInput {
|
|
||||||
kind: MemberMessageKind;
|
|
||||||
title: string;
|
|
||||||
subtitle: string;
|
|
||||||
username: string;
|
|
||||||
avatarUrl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CARD_WIDTH = 1024;
|
const CARD_WIDTH = 1024;
|
||||||
const CARD_HEIGHT = 320;
|
const CARD_HEIGHT = 320;
|
||||||
|
|||||||
@@ -5,48 +5,27 @@ import {
|
|||||||
MessageFlags,
|
MessageFlags,
|
||||||
PermissionFlagsBits,
|
PermissionFlagsBits,
|
||||||
TextDisplayBuilder,
|
TextDisplayBuilder,
|
||||||
type Client,
|
|
||||||
type Guild,
|
type Guild,
|
||||||
type MessageCreateOptions,
|
type MessageCreateOptions,
|
||||||
type User,
|
type User,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
import type { I18nService } from "../../i18n/index.js";
|
import type { I18nService } from "../../i18n/index.js";
|
||||||
import type { SupportedLang } from "../types/command.js";
|
import type { SupportedLang } from "../../types/command.js";
|
||||||
|
import type {
|
||||||
|
DispatchMemberMessageInput,
|
||||||
|
DispatchMemberMessageResult,
|
||||||
|
MemberMessageKind,
|
||||||
|
MemberMessageRenderType,
|
||||||
|
SendableChannel,
|
||||||
|
TemplateSuffix,
|
||||||
|
} from "../../types/memberMessages.js";
|
||||||
import { renderMemberMessageImage } from "./memberMessageImage.js";
|
import { renderMemberMessageImage } from "./memberMessageImage.js";
|
||||||
import { getMemberMessageStore } from "./memberMessageStore.js";
|
import { getMemberMessageStore } from "./memberMessageStore.js";
|
||||||
import {
|
export type {
|
||||||
type MemberMessageKind,
|
DispatchMemberMessageFailureReason,
|
||||||
type MemberMessageRenderType,
|
DispatchMemberMessageResult,
|
||||||
} from "./memberMessageTypes.js";
|
} from "../../types/memberMessages.js";
|
||||||
|
|
||||||
export type DispatchMemberMessageFailureReason =
|
|
||||||
| "bot_not_ready"
|
|
||||||
| "disabled"
|
|
||||||
| "missing_channel"
|
|
||||||
| "channel_not_found"
|
|
||||||
| "channel_not_sendable"
|
|
||||||
| "missing_permissions"
|
|
||||||
| "send_failed";
|
|
||||||
|
|
||||||
export interface DispatchMemberMessageResult {
|
|
||||||
sent: boolean;
|
|
||||||
reason: DispatchMemberMessageFailureReason | "sent";
|
|
||||||
channelId: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DispatchMemberMessageInput {
|
|
||||||
client: Client;
|
|
||||||
i18n?: I18nService;
|
|
||||||
guild: Guild;
|
|
||||||
user: User;
|
|
||||||
kind: MemberMessageKind;
|
|
||||||
ignoreEnabled?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SendableChannel {
|
|
||||||
send: (payload: string | MessageCreateOptions) => Promise<unknown>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasSendMethod = (value: unknown): value is SendableChannel => {
|
const hasSendMethod = (value: unknown): value is SendableChannel => {
|
||||||
if (!value || typeof value !== "object") {
|
if (!value || typeof value !== "object") {
|
||||||
@@ -74,15 +53,6 @@ const messageColor = (kind: MemberMessageKind): number => {
|
|||||||
return kind === "welcome" ? 0x57f287 : 0xed4245;
|
return kind === "welcome" ? 0x57f287 : 0xed4245;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TemplateSuffix =
|
|
||||||
| "simple"
|
|
||||||
| "embedTitle"
|
|
||||||
| "embedDescription"
|
|
||||||
| "containerTitle"
|
|
||||||
| "containerDescription"
|
|
||||||
| "imageTitle"
|
|
||||||
| "imageDescription";
|
|
||||||
|
|
||||||
const defaultTemplate = (
|
const defaultTemplate = (
|
||||||
kind: MemberMessageKind,
|
kind: MemberMessageKind,
|
||||||
suffix: TemplateSuffix,
|
suffix: TemplateSuffix,
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
import { Pool } from "pg";
|
import { Pool } from "pg";
|
||||||
|
|
||||||
import { env } from "../config/env.js";
|
import { env } from "../config/env.js";
|
||||||
|
import type {
|
||||||
|
MemberMessageConfig,
|
||||||
|
MemberMessageKind,
|
||||||
|
MemberMessageRow,
|
||||||
|
} from "../../types/memberMessages.js";
|
||||||
import {
|
import {
|
||||||
createDefaultMemberMessageConfig,
|
createDefaultMemberMessageConfig,
|
||||||
isMemberMessageRenderTypeValue,
|
isMemberMessageRenderTypeValue,
|
||||||
type MemberMessageConfig,
|
|
||||||
type MemberMessageKind,
|
|
||||||
} from "./memberMessageTypes.js";
|
} from "./memberMessageTypes.js";
|
||||||
|
|
||||||
interface MemberMessageRow {
|
|
||||||
enabled: boolean;
|
|
||||||
channel_id: string | null;
|
|
||||||
message_type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableSql = `
|
const tableSql = `
|
||||||
CREATE TABLE IF NOT EXISTS bot_member_message_configs (
|
CREATE TABLE IF NOT EXISTS bot_member_message_configs (
|
||||||
bot_id TEXT NOT NULL,
|
bot_id TEXT NOT NULL,
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
export const MEMBER_MESSAGE_KINDS = ["welcome", "goodbye"] as const;
|
import type {
|
||||||
export type MemberMessageKind = (typeof MEMBER_MESSAGE_KINDS)[number];
|
MemberMessageConfig,
|
||||||
|
MemberMessageKind,
|
||||||
|
MemberMessageRenderType,
|
||||||
|
} from "../../types/memberMessages.js";
|
||||||
|
|
||||||
export const MEMBER_MESSAGE_RENDER_TYPES = ["simple", "embed", "container", "image"] as const;
|
export type { MemberMessageConfig, MemberMessageKind, MemberMessageRenderType } from "../../types/memberMessages.js";
|
||||||
export type MemberMessageRenderType = (typeof MEMBER_MESSAGE_RENDER_TYPES)[number];
|
|
||||||
|
export const MEMBER_MESSAGE_KINDS: readonly MemberMessageKind[] = ["welcome", "goodbye"];
|
||||||
|
|
||||||
|
export const MEMBER_MESSAGE_RENDER_TYPES: readonly MemberMessageRenderType[] = ["simple", "embed", "container", "image"];
|
||||||
|
|
||||||
export const DEFAULT_MEMBER_MESSAGE_RENDER_TYPE: MemberMessageRenderType = "simple";
|
export const DEFAULT_MEMBER_MESSAGE_RENDER_TYPE: MemberMessageRenderType = "simple";
|
||||||
|
|
||||||
export interface MemberMessageConfig {
|
|
||||||
enabled: boolean;
|
|
||||||
channelId: string | null;
|
|
||||||
messageType: MemberMessageRenderType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createDefaultMemberMessageConfig = (): MemberMessageConfig => ({
|
export const createDefaultMemberMessageConfig = (): MemberMessageConfig => ({
|
||||||
enabled: false,
|
enabled: false,
|
||||||
channelId: null,
|
channelId: null,
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { Pool } from "pg";
|
import { Pool } from "pg";
|
||||||
|
|
||||||
import { env } from "../config/env.js";
|
import { env } from "../config/env.js";
|
||||||
|
import type {
|
||||||
|
PresenceActivityTypeValue,
|
||||||
|
PresenceRow,
|
||||||
|
PresenceState,
|
||||||
|
PresenceStatusValue,
|
||||||
|
} from "../../types/presence.js";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ACTIVITY_ROTATION_INTERVAL_SECONDS,
|
DEFAULT_ACTIVITY_ROTATION_INTERVAL_SECONDS,
|
||||||
createDefaultPresenceState,
|
createDefaultPresenceState,
|
||||||
@@ -9,19 +15,8 @@ import {
|
|||||||
sanitizeActivityText,
|
sanitizeActivityText,
|
||||||
sanitizeActivityTexts,
|
sanitizeActivityTexts,
|
||||||
sanitizePresenceRotationIntervalSeconds,
|
sanitizePresenceRotationIntervalSeconds,
|
||||||
type PresenceActivityTypeValue,
|
|
||||||
type PresenceState,
|
|
||||||
type PresenceStatusValue,
|
|
||||||
} from "./presenceTypes.js";
|
} from "./presenceTypes.js";
|
||||||
|
|
||||||
interface PresenceRow {
|
|
||||||
status: string;
|
|
||||||
activity_type: string;
|
|
||||||
activity_text: string;
|
|
||||||
activity_texts: string | null;
|
|
||||||
rotation_interval_seconds: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableSql = `
|
const tableSql = `
|
||||||
CREATE TABLE IF NOT EXISTS bot_presence_states (
|
CREATE TABLE IF NOT EXISTS bot_presence_states (
|
||||||
bot_id TEXT PRIMARY KEY,
|
bot_id TEXT PRIMARY KEY,
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
export const PRESENCE_STATUSES = ["online", "idle", "dnd", "invisible", "streaming"] as const;
|
import type {
|
||||||
export const PRESENCE_ACTIVITY_TYPES = [
|
PresenceActivityTypeValue,
|
||||||
|
PresenceState,
|
||||||
|
PresenceStatusValue,
|
||||||
|
} from "../../types/presence.js";
|
||||||
|
|
||||||
|
export const PRESENCE_STATUSES: readonly PresenceStatusValue[] = ["online", "idle", "dnd", "invisible", "streaming"];
|
||||||
|
export const PRESENCE_ACTIVITY_TYPES: readonly PresenceActivityTypeValue[] = [
|
||||||
"PLAYING",
|
"PLAYING",
|
||||||
"STREAMING",
|
"STREAMING",
|
||||||
"WATCHING",
|
"WATCHING",
|
||||||
"LISTENING",
|
"LISTENING",
|
||||||
"COMPETING",
|
"COMPETING",
|
||||||
"CUSTOM",
|
"CUSTOM",
|
||||||
] as const;
|
];
|
||||||
|
|
||||||
export type PresenceStatusValue = (typeof PRESENCE_STATUSES)[number];
|
|
||||||
export type PresenceActivityTypeValue = (typeof PRESENCE_ACTIVITY_TYPES)[number];
|
|
||||||
|
|
||||||
export const DEFAULT_ACTIVITY_TEXT = "Ready to help";
|
export const DEFAULT_ACTIVITY_TEXT = "Ready to help";
|
||||||
export const DEFAULT_ACTIVITY_ROTATION_INTERVAL_SECONDS = 30;
|
export const DEFAULT_ACTIVITY_ROTATION_INTERVAL_SECONDS = 30;
|
||||||
@@ -17,16 +20,6 @@ export const MIN_ACTIVITY_ROTATION_INTERVAL_SECONDS = 5;
|
|||||||
export const MAX_ACTIVITY_ROTATION_INTERVAL_SECONDS = 3_600;
|
export const MAX_ACTIVITY_ROTATION_INTERVAL_SECONDS = 3_600;
|
||||||
export const MAX_ACTIVITY_ROTATION_TEXTS = 10;
|
export const MAX_ACTIVITY_ROTATION_TEXTS = 10;
|
||||||
|
|
||||||
export interface PresenceState {
|
|
||||||
status: PresenceStatusValue;
|
|
||||||
activity: {
|
|
||||||
type: PresenceActivityTypeValue;
|
|
||||||
text: string;
|
|
||||||
texts: string[];
|
|
||||||
rotationIntervalSeconds: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createDefaultPresenceState = (): PresenceState => ({
|
export const createDefaultPresenceState = (): PresenceState => ({
|
||||||
status: "online",
|
status: "online",
|
||||||
activity: {
|
activity: {
|
||||||
@@ -38,10 +31,10 @@ export const createDefaultPresenceState = (): PresenceState => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const isPresenceStatusValue = (value: string): value is PresenceStatusValue =>
|
export const isPresenceStatusValue = (value: string): value is PresenceStatusValue =>
|
||||||
(PRESENCE_STATUSES as readonly string[]).includes(value);
|
PRESENCE_STATUSES.includes(value as PresenceStatusValue);
|
||||||
|
|
||||||
export const isPresenceActivityTypeValue = (value: string): value is PresenceActivityTypeValue =>
|
export const isPresenceActivityTypeValue = (value: string): value is PresenceActivityTypeValue =>
|
||||||
(PRESENCE_ACTIVITY_TYPES as readonly string[]).includes(value);
|
PRESENCE_ACTIVITY_TYPES.includes(value as PresenceActivityTypeValue);
|
||||||
|
|
||||||
export const sanitizeActivityText = (value: string): string => {
|
export const sanitizeActivityText = (value: string): string => {
|
||||||
const trimmed = value.trim();
|
const trimmed = value.trim();
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
export interface TemplateRenderOptions {
|
import type { TemplateRenderOptions } from "../../types/templateVariables.js";
|
||||||
aliases?: Record<string, string>;
|
|
||||||
keepUnknown?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createTemplateTokenRegex = (): RegExp => /\{\{([a-zA-Z0-9_]+)\}\}/g;
|
const createTemplateTokenRegex = (): RegExp => /\{\{([a-zA-Z0-9_]+)\}\}/g;
|
||||||
|
|
||||||
|
|||||||
+2
-24
@@ -1,32 +1,10 @@
|
|||||||
import type { CommandRegistry } from "../commands/registry.js";
|
|
||||||
import type { I18nService } from "../../i18n/index.js";
|
|
||||||
import type {
|
import type {
|
||||||
BotCommand,
|
|
||||||
CommandExecutionContext,
|
CommandExecutionContext,
|
||||||
CommandSource,
|
|
||||||
SupportedLang,
|
SupportedLang,
|
||||||
TranslationVars,
|
TranslationVars,
|
||||||
} from "../types/command.js";
|
} from "../types/command.js";
|
||||||
|
import type { BuildExecutionContextInput, HandlerExecutionDeps } from "../types/handlers.js";
|
||||||
export interface HandlerExecutionDeps {
|
import type { I18nService } from "../i18n/index.js";
|
||||||
registry: CommandRegistry;
|
|
||||||
i18n: I18nService;
|
|
||||||
prefix: string;
|
|
||||||
defaultLang: SupportedLang;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BuildExecutionContextInput {
|
|
||||||
command: BotCommand;
|
|
||||||
source: CommandSource;
|
|
||||||
lang: SupportedLang;
|
|
||||||
args: CommandExecutionContext["args"];
|
|
||||||
client: CommandExecutionContext["client"];
|
|
||||||
user: CommandExecutionContext["user"];
|
|
||||||
guild: CommandExecutionContext["guild"];
|
|
||||||
channel: CommandExecutionContext["channel"];
|
|
||||||
raw: CommandExecutionContext["raw"];
|
|
||||||
reply: CommandExecutionContext["reply"];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createTranslator = (
|
export const createTranslator = (
|
||||||
i18n: I18nService,
|
i18n: I18nService,
|
||||||
@@ -1,20 +1,15 @@
|
|||||||
import type { Message } from "discord.js";
|
import type { Message } from "discord.js";
|
||||||
import type { BotCommand, SupportedLang } from "../types/command.js";
|
import type { BotCommand, SupportedLang } from "../types/command.js";
|
||||||
|
import type { PrefixHandlerDeps } from "../types/handlers.js";
|
||||||
|
|
||||||
import { parsePrefixArgs } from "../commands/argParser.js";
|
import { parsePrefixArgs } from "../framework/commands/argParser.js";
|
||||||
import { buildPrefixUsage } from "../commands/usage.js";
|
import { buildPrefixUsage } from "../framework/commands/usage.js";
|
||||||
import { CommandExecutor } from "../execution/CommandExecutor.js";
|
|
||||||
import {
|
import {
|
||||||
buildCommandExecutionContext,
|
buildCommandExecutionContext,
|
||||||
createTranslator,
|
createTranslator,
|
||||||
type HandlerExecutionDeps,
|
|
||||||
} from "./commandExecutionContext.js";
|
} from "./commandExecutionContext.js";
|
||||||
import { createPrefixReply } from "./replyAdapter.js";
|
import { createPrefixReply } from "./replyAdapter.js";
|
||||||
|
|
||||||
interface PrefixHandlerDeps extends HandlerExecutionDeps {
|
|
||||||
executor: CommandExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolvePrefixLang = (
|
const resolvePrefixLang = (
|
||||||
deps: PrefixHandlerDeps,
|
deps: PrefixHandlerDeps,
|
||||||
command: BotCommand,
|
command: BotCommand,
|
||||||
@@ -6,6 +6,7 @@ import type {
|
|||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
import type { ReplyPayload } from "../types/command.js";
|
import type { ReplyPayload } from "../types/command.js";
|
||||||
|
import type { PrefixReplyObject } from "../types/reply.js";
|
||||||
|
|
||||||
const PREFIX_EPHEMERAL_DELETE_DELAY_MS = 10_000;
|
const PREFIX_EPHEMERAL_DELETE_DELAY_MS = 10_000;
|
||||||
|
|
||||||
@@ -18,8 +19,6 @@ const SLASH_ALLOWED_MENTIONS_DEFAULT: NonNullable<InteractionReplyOptions["allow
|
|||||||
parse: [],
|
parse: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
type PrefixReplyObject = Exclude<ReplyPayload, string>;
|
|
||||||
|
|
||||||
const EPHEMERAL_FLAG = 64n;
|
const EPHEMERAL_FLAG = 64n;
|
||||||
const FLAG_NAME_TO_BITS: Record<string, bigint> = {
|
const FLAG_NAME_TO_BITS: Record<string, bigint> = {
|
||||||
Ephemeral: 64n,
|
Ephemeral: 64n,
|
||||||
@@ -1,19 +1,14 @@
|
|||||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||||
|
import type { SlashHandlerDeps } from "../types/handlers.js";
|
||||||
|
|
||||||
import { parseSlashArgs } from "../commands/argParser.js";
|
import { parseSlashArgs } from "../framework/commands/argParser.js";
|
||||||
import { buildSlashUsage } from "../commands/usage.js";
|
import { buildSlashUsage } from "../framework/commands/usage.js";
|
||||||
import { CommandExecutor } from "../execution/CommandExecutor.js";
|
|
||||||
import {
|
import {
|
||||||
buildCommandExecutionContext,
|
buildCommandExecutionContext,
|
||||||
createTranslator,
|
createTranslator,
|
||||||
type HandlerExecutionDeps,
|
|
||||||
} from "./commandExecutionContext.js";
|
} from "./commandExecutionContext.js";
|
||||||
import { createSlashReply } from "./replyAdapter.js";
|
import { createSlashReply } from "./replyAdapter.js";
|
||||||
|
|
||||||
interface SlashHandlerDeps extends HandlerExecutionDeps {
|
|
||||||
executor: CommandExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createSlashHandler = (deps: SlashHandlerDeps) => {
|
export const createSlashHandler = (deps: SlashHandlerDeps) => {
|
||||||
return async (interaction: ChatInputCommandInteraction): Promise<void> => {
|
return async (interaction: ChatInputCommandInteraction): Promise<void> => {
|
||||||
const command = deps.registry.findBySlashTrigger(interaction.commandName);
|
const command = deps.registry.findBySlashTrigger(interaction.commandName);
|
||||||
+2
-3
@@ -2,9 +2,8 @@ import { existsSync, readFileSync } from "node:fs";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
import { SUPPORTED_LANGS, type SupportedLang, type TranslationVars } from "../framework/types/command.js";
|
import { SUPPORTED_LANGS, type SupportedLang, type TranslationVars } from "../types/command.js";
|
||||||
|
import type { JsonObject } from "../types/i18n.js";
|
||||||
type JsonObject = Record<string, unknown>;
|
|
||||||
|
|
||||||
const DISCORD_LOCALE_MAP: Record<string, SupportedLang> = {
|
const DISCORD_LOCALE_MAP: Record<string, SupportedLang> = {
|
||||||
en: "en",
|
en: "en",
|
||||||
|
|||||||
+2
-2
@@ -16,8 +16,8 @@ import { registerEvents } from "./events/index.js";
|
|||||||
import { CommandRegistry } from "./framework/commands/registry.js";
|
import { CommandRegistry } from "./framework/commands/registry.js";
|
||||||
import { env } from "./framework/config/env.js";
|
import { env } from "./framework/config/env.js";
|
||||||
import { CommandExecutor } from "./framework/execution/CommandExecutor.js";
|
import { CommandExecutor } from "./framework/execution/CommandExecutor.js";
|
||||||
import { createPrefixHandler } from "./framework/handlers/prefixHandler.js";
|
import { createPrefixHandler } from "./handlers/prefixHandler.js";
|
||||||
import { createSlashHandler } from "./framework/handlers/slashHandler.js";
|
import { createSlashHandler } from "./handlers/slashHandler.js";
|
||||||
import { I18nService } from "./i18n/index.js";
|
import { I18nService } from "./i18n/index.js";
|
||||||
import {
|
import {
|
||||||
initMemberMessageStore,
|
initMemberMessageStore,
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import type { CommandArgValue, TranslationVars } from "./command.js";
|
||||||
|
|
||||||
|
export interface ArgumentParseError {
|
||||||
|
key: string;
|
||||||
|
vars?: TranslationVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ParsedArgumentsResult {
|
||||||
|
values: Record<string, CommandArgValue>;
|
||||||
|
errors: ArgumentParseError[];
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import type { CommandRegistry } from "../framework/commands/registry.js";
|
||||||
|
import type { I18nService } from "../i18n/index.js";
|
||||||
|
|
||||||
|
export interface DeployCommandsOptions {
|
||||||
|
token: string;
|
||||||
|
clientId: string;
|
||||||
|
guildId?: string;
|
||||||
|
registry: CommandRegistry;
|
||||||
|
i18n: I18nService;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeployCommandsResult {
|
||||||
|
scope: "guild" | "global";
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import type { CommandRegistry } from "../framework/commands/registry.js";
|
||||||
|
import type { CommandExecutor } from "../framework/execution/CommandExecutor.js";
|
||||||
|
import type { I18nService } from "../i18n/index.js";
|
||||||
|
import type {
|
||||||
|
BotCommand,
|
||||||
|
CommandExecutionContext,
|
||||||
|
CommandSource,
|
||||||
|
SupportedLang,
|
||||||
|
} from "./command.js";
|
||||||
|
|
||||||
|
export interface HandlerExecutionDeps {
|
||||||
|
registry: CommandRegistry;
|
||||||
|
i18n: I18nService;
|
||||||
|
prefix: string;
|
||||||
|
defaultLang: SupportedLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuildExecutionContextInput {
|
||||||
|
command: BotCommand;
|
||||||
|
source: CommandSource;
|
||||||
|
lang: SupportedLang;
|
||||||
|
args: CommandExecutionContext["args"];
|
||||||
|
client: CommandExecutionContext["client"];
|
||||||
|
user: CommandExecutionContext["user"];
|
||||||
|
guild: CommandExecutionContext["guild"];
|
||||||
|
channel: CommandExecutionContext["channel"];
|
||||||
|
raw: CommandExecutionContext["raw"];
|
||||||
|
reply: CommandExecutionContext["reply"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrefixHandlerDeps extends HandlerExecutionDeps {
|
||||||
|
executor: CommandExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SlashHandlerDeps extends HandlerExecutionDeps {
|
||||||
|
executor: CommandExecutor;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export type JsonObject = Record<string, unknown>;
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import type {
|
||||||
|
Client,
|
||||||
|
Guild,
|
||||||
|
Message,
|
||||||
|
MessageCreateOptions,
|
||||||
|
User,
|
||||||
|
} from "discord.js";
|
||||||
|
|
||||||
|
import type { I18nService } from "../i18n/index.js";
|
||||||
|
|
||||||
|
export type MemberMessageKind = "welcome" | "goodbye";
|
||||||
|
export type MemberMessageRenderType = "simple" | "embed" | "container" | "image";
|
||||||
|
|
||||||
|
export interface MemberMessageConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
channelId: string | null;
|
||||||
|
messageType: MemberMessageRenderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DispatchMemberMessageFailureReason =
|
||||||
|
| "bot_not_ready"
|
||||||
|
| "disabled"
|
||||||
|
| "missing_channel"
|
||||||
|
| "channel_not_found"
|
||||||
|
| "channel_not_sendable"
|
||||||
|
| "missing_permissions"
|
||||||
|
| "send_failed";
|
||||||
|
|
||||||
|
export interface DispatchMemberMessageResult {
|
||||||
|
sent: boolean;
|
||||||
|
reason: DispatchMemberMessageFailureReason | "sent";
|
||||||
|
channelId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DispatchMemberMessageInput {
|
||||||
|
client: Client;
|
||||||
|
i18n?: I18nService;
|
||||||
|
guild: Guild;
|
||||||
|
user: User;
|
||||||
|
kind: MemberMessageKind;
|
||||||
|
ignoreEnabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SendableChannel {
|
||||||
|
send: (payload: string | MessageCreateOptions) => Promise<unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TemplateSuffix =
|
||||||
|
| "simple"
|
||||||
|
| "embedTitle"
|
||||||
|
| "embedDescription"
|
||||||
|
| "containerTitle"
|
||||||
|
| "containerDescription"
|
||||||
|
| "imageTitle"
|
||||||
|
| "imageDescription";
|
||||||
|
|
||||||
|
export interface MemberMessageImageInput {
|
||||||
|
kind: MemberMessageKind;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
username: string;
|
||||||
|
avatarUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberMessageRow {
|
||||||
|
enabled: boolean;
|
||||||
|
channel_id: string | null;
|
||||||
|
message_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberMessageCustomIds {
|
||||||
|
toggleButton: string;
|
||||||
|
channelButton: string;
|
||||||
|
channelCancelButton: string;
|
||||||
|
typeSelect: string;
|
||||||
|
channelSelect: string;
|
||||||
|
testButton: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberMessagePanelUiState {
|
||||||
|
channelPickerOpen: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemberMessagePanelSession {
|
||||||
|
collector: ReturnType<Message["createMessageComponentCollector"]>;
|
||||||
|
disable: () => Promise<void>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import type { Message } from "discord.js";
|
||||||
|
|
||||||
|
export type PresenceStatusValue = "online" | "idle" | "dnd" | "invisible" | "streaming";
|
||||||
|
export type PresenceActivityTypeValue = "PLAYING" | "STREAMING" | "WATCHING" | "LISTENING" | "COMPETING" | "CUSTOM";
|
||||||
|
|
||||||
|
export interface PresenceActivityState {
|
||||||
|
type: PresenceActivityTypeValue;
|
||||||
|
text: string;
|
||||||
|
texts: string[];
|
||||||
|
rotationIntervalSeconds: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PresenceState {
|
||||||
|
status: PresenceStatusValue;
|
||||||
|
activity: PresenceActivityState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PresenceRow {
|
||||||
|
status: string;
|
||||||
|
activity_type: string;
|
||||||
|
activity_text: string;
|
||||||
|
activity_texts: string | null;
|
||||||
|
rotation_interval_seconds: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PresenceCustomIds {
|
||||||
|
statusSelect: string;
|
||||||
|
activitySelect: string;
|
||||||
|
textButton: string;
|
||||||
|
intervalButton: string;
|
||||||
|
textModal: string;
|
||||||
|
textInput: string;
|
||||||
|
intervalModal: string;
|
||||||
|
intervalInput: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PresencePanelSession {
|
||||||
|
collector: ReturnType<Message["createMessageComponentCollector"]>;
|
||||||
|
disable: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PresenceRuntimeState {
|
||||||
|
dynamicPresenceRefreshTimer: NodeJS.Timeout | null;
|
||||||
|
presenceRotationTimer: NodeJS.Timeout | null;
|
||||||
|
activePresenceTextIndex: number;
|
||||||
|
activePanelsByUserId: Map<string, PresencePanelSession>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DiscordPresenceStatus = "online" | "idle" | "dnd" | "invisible";
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import type { ReplyPayload } from "./command.js";
|
||||||
|
|
||||||
|
export type PrefixReplyObject = Exclude<ReplyPayload, string>;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export interface TemplateRenderOptions {
|
||||||
|
aliases?: Record<string, string>;
|
||||||
|
keepUnknown?: boolean;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user