feat: better subcommand organiztion

This commit is contained in:
TresAbhi committed 2023-08-04 02:13:21 +00:00
1 parent 2cabcc57f4
commit 23dd088466
15 files changed
+749 -867

No files matched your search

+1 -1
View File
@@ -29,4 +29,4 @@ jobs:
unzip dist.zip
- name: Run bot
run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ secrets.WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings bot.cjs
run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ secrets.WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings bot.js
+3 -2
View File
@@ -1,6 +1,7 @@
{
"main": "server.cjs",
"main": "server.js",
"type": "module",
"scripts": {
"start": "node --enable-source-maps --trace-warnings server.cjs"
"start": "node --enable-source-maps --trace-warnings server.js"
}
}
+1 -1
View File
@@ -27,7 +27,7 @@
"@radix-ui/colors": "^0.1.8",
"@resvg/resvg-js": "^2.4.1",
"bepaint": "^0.1.0-beta.3",
"discord.js": "^14.9.0",
"discord.js": "^14.12.0",
"esbuild": "^0.18.10",
"escape-html": "^1.0.3",
"express": "^4.18.2",
+5 -4
View File
@@ -1,5 +1,5 @@
import { BuildOptions, build } from 'esbuild';
import { copyFile, mkdir, rm } from 'fs/promises';
import { copyFile, mkdirSync, rmSync } from 'fs';
import { argv } from 'process';
const isProd = !argv.includes('--dev');
@@ -10,15 +10,15 @@ const buildServer = argv.includes('--build=server') || buildAll;
if (isProd) {
// only remove in production to ensure no time is wasted in dev
console.log('Removing dist...');
await rm('dist', { recursive: true, force: true });
rmSync('dist', { recursive: true, force: true });
console.log('Dist removed');
console.log('Creating dist...');
await mkdir('dist');
mkdirSync('dist');
console.log('Dist created');
console.log('Copying package.json...');
copyFile('package.dist.json', 'dist/package.json').then(() =>
copyFile('package.dist.json', 'dist/package.json', () =>
console.log('package.json copied'),
);
}
@@ -29,6 +29,7 @@ const commonOptions: BuildOptions = {
'.node': 'copy',
'.ttf': 'file',
},
format: 'cjs',
bundle: true,
sourcemap: true,
+72 -66
View File
@@ -13,75 +13,81 @@ import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
import { secrets } from '../core/node/secrets';
import { CommandRegistry } from '../events/interactionCreate';
import { CommandRegistryRaw } from '../events/interactionCreate';
import evolution from '../renderers/evolution';
import { StatType } from '../renderers/fullStats';
import { AccountInfo } from '../types/accountInfo';
export const evolutionCommand: CommandRegistry = {
inProduction: true,
inDevelopment: false,
inPublic: true,
command: addStatTypeSubCommandGroups(
new SlashCommandBuilder()
.setName('evolution')
.setDescription('Evolution of statistics'),
),
async handler(interaction) {
const commandGroup = interaction.options.getSubcommandGroup(
true,
) as StatType;
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const tankIdRaw = interaction.options.getString('tank')!;
const tankId =
commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
return [
await evolution(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
// linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}${
commandGroup === 'tank' ? `/tank/${tankId!}` : ''
}`,
'BlitzStars',
),
];
},
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
},
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return await evolution(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
export const evolutionCommand = new Promise<CommandRegistryRaw>(
async (resolve) => {
const command = await addStatTypeSubCommandGroups(
new SlashCommandBuilder()
.setName('evolution')
.setDescription('Evolution of statistics'),
);
resolve({
inProduction: true,
inDevelopment: false,
inPublic: true,
command,
async handler(interaction) {
const commandGroup = interaction.options.getSubcommandGroup(
true,
) as StatType;
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const tankIdRaw = interaction.options.getString('tank')!;
const tankId =
commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
return [
await evolution(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
// linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}${
commandGroup === 'tank' ? `/tank/${tankId!}` : ''
}`,
'BlitzStars',
),
];
},
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
},
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return await evolution(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
);
},
});
},
};
);
+70 -64
View File
@@ -13,72 +13,78 @@ import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
import { secrets } from '../core/node/secrets';
import { CommandRegistry } from '../events/interactionCreate';
import { CommandRegistryRaw } from '../events/interactionCreate';
import fullStats, { StatType } from '../renderers/fullStats';
import { AccountInfo } from '../types/accountInfo';
export const fullStatsCommand: CommandRegistry = {
inProduction: true,
inDevelopment: false,
inPublic: true,
command: addStatTypeSubCommandGroups(
new SlashCommandBuilder()
.setName('fullstats')
.setDescription('Full in-game statistics'),
),
async handler(interaction) {
const commandGroup = interaction.options.getSubcommandGroup(
true,
) as StatType;
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const tankIdRaw = interaction.options.getString('tank')!;
const tankId =
commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
return [
await fullStats(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
// linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}`,
'BlitzStars',
),
];
},
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
},
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return await fullStats(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
export const fullStatsCommand = new Promise<CommandRegistryRaw>(
async (resolve) => {
const command = await addStatTypeSubCommandGroups(
new SlashCommandBuilder()
.setName('fullstats')
.setDescription('Full in-game statistics'),
);
resolve({
inProduction: true,
inDevelopment: false,
inPublic: true,
command,
async handler(interaction) {
const commandGroup = interaction.options.getSubcommandGroup(
true,
) as StatType;
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const tankIdRaw = interaction.options.getString('tank')!;
const tankId =
commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
return [
await fullStats(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
// linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}`,
'BlitzStars',
),
];
},
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
},
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return await fullStats(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
);
},
});
},
};
);
+1 -2
View File
@@ -121,7 +121,7 @@ export const DATABASE_REPO = { owner: 'tresabhi', repo: 'blitzkrieg-db' };
export const ratingsCommand: CommandRegistry = {
inProduction: true,
inDevelopment: true,
inDevelopment: false,
inPublic: true,
command: new SlashCommandBuilder()
@@ -165,7 +165,6 @@ export const ratingsCommand: CommandRegistry = {
),
),
),
async handler(interaction) {
const subcommandGroup = interaction.options.getSubcommandGroup(true);
+62 -58
View File
@@ -13,73 +13,77 @@ import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand';
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton';
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
import { secrets } from '../core/node/secrets';
import { CommandRegistry } from '../events/interactionCreate';
import { CommandRegistryRaw } from '../events/interactionCreate';
import { StatType } from '../renderers/fullStats';
import stats from '../renderers/stats';
import { AccountInfo } from '../types/accountInfo';
export const statsCommand: CommandRegistry = {
inProduction: true,
inDevelopment: false,
inPublic: true,
command: addStatTypeSubCommandGroups(
export const statsCommand = new Promise<CommandRegistryRaw>(async (resolve) => {
const command = await addStatTypeSubCommandGroups(
new SlashCommandBuilder()
.setName('stats')
.setDescription('Regular battles statistics'),
),
);
async handler(interaction) {
const commandGroup = interaction.options.getSubcommandGroup(
true,
) as StatType;
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const tankIdRaw = interaction.options.getString('tank')!;
const tankId =
commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
resolve({
inProduction: true,
inDevelopment: true,
inPublic: true,
return [
await stats(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}`,
'BlitzStars',
),
];
},
command,
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
},
async handler(interaction) {
const commandGroup = interaction.options.getSubcommandGroup(
true,
) as StatType;
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const tankIdRaw = interaction.options.getString('tank')!;
const tankId =
commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null;
const start = interaction.options.getInteger('start');
const end = interaction.options.getInteger('end');
const path = interactionToURL(interaction, {
...player,
tankId,
start,
end,
});
const { nickname } = (
await getWargamingResponse<AccountInfo>(
`https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${player.id}`,
)
)[player.id];
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return [
await stats(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
linkButton(`${CYCLIC_API}/${path}`, 'Embed'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}`,
'BlitzStars',
),
];
},
return await stats(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
);
},
};
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
},
async button(interaction) {
const url = new URL(`${CYCLIC_API}/${interaction.customId}`);
const path = url.pathname.split('/').filter(Boolean);
const commandGroup = path[1] as StatType;
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return await stats(
commandGroup,
period,
player,
parseInt(url.searchParams.get('tankId')!),
);
},
});
});
+19
View File
@@ -1,3 +1,6 @@
import { secrets } from '../node/secrets';
import getWargamingResponse from './getWargamingResponse';
export interface TankopediaEntry {
name: string;
nation: string;
@@ -32,6 +35,22 @@ export const TANK_NAMES = new Promise<string[]>(async (resolve) => {
resolve((await entries).map(({ name }) => name));
});
export interface TankopediaInfo {
achievement_sections: Record<string, { name: string; order: number }>;
tanks_updated_at: number;
languages: Record<string, string>;
vehicle_types: Record<string, string>;
vehicle_nations: Record<string, string>;
game_version: string;
}
// this is blocking because info is needed for command creation
console.log('Caching tankopedia info...');
export const tankopediaInfo = getWargamingResponse<TankopediaInfo>(
`https://api.wotblitz.com/wotb/encyclopedia/info/?application_id=${secrets.WARGAMING_APPLICATION_ID}`,
);
console.log('Cached tankopedia info');
export const TANK_ICONS: Record<string, string> = {
'AT-SPG': 'https://i.imgur.com/BIHSEH0.png',
lightTank: 'https://i.imgur.com/CSNha5V.png',
+2 -2
View File
@@ -4,13 +4,13 @@ import getTimeDaysAgo from './getTimeDaysAgo';
export default function getPeriodStart(
server: Region,
period: Exclude<Period, 'custom'>,
period: Exclude<Period, 'customperiod'>,
) {
if (period === 'career') {
return -Infinity;
} else if (period === 'today') {
return getTimeDaysAgo(server, 1);
} else {
return getTimeDaysAgo(server, parseInt(period));
return getTimeDaysAgo(server, parseInt(period.match(/\d+/)?.[0]!));
}
}
+21 -16
View File
@@ -4,7 +4,7 @@ import {
} from 'discord.js';
import { PERIOD_NAMES } from '../discord/resolvePeriodFromCommand';
export type Period = 'today' | '30' | '60' | '90' | 'career' | 'custom';
export type Period = 'period' | 'customperiod';
export default function addPeriodSubCommands(
option: SlashCommandSubcommandGroupBuilder,
@@ -14,25 +14,30 @@ export default function addPeriodSubCommands(
) {
return option
.addSubcommand((option) =>
extra(option.setName('today').setDescription(PERIOD_NAMES.today)),
)
.addSubcommand((option) =>
extra(option.setName('30').setDescription(PERIOD_NAMES[30])),
)
.addSubcommand((option) =>
extra(option.setName('60').setDescription(PERIOD_NAMES[60])),
)
.addSubcommand((option) =>
extra(option.setName('90').setDescription(PERIOD_NAMES[90])),
)
.addSubcommand((option) =>
extra(option.setName('career').setDescription(PERIOD_NAMES.career)),
extra(
option
.setName('period' satisfies Period)
.setDescription(PERIOD_NAMES.period)
.addStringOption((option) =>
option
.setName('days')
.setDescription('A preset period')
.setChoices(
{ name: 'Today', value: '1' },
{ name: '30 days', value: '30' },
{ name: '60 days', value: '60' },
{ name: '90 days', value: '90' },
{ name: 'Career', value: 'Infinity' },
)
.setRequired(true),
),
),
)
.addSubcommand((option) =>
extra(
option
.setName('custom')
.setDescription(PERIOD_NAMES.custom)
.setName('customperiod' satisfies Period)
.setDescription(PERIOD_NAMES.customperiod)
.addIntegerOption((option) =>
option
.setName('start')
@@ -1,18 +1,21 @@
import { SlashCommandBuilder } from 'discord.js';
import { tankopediaInfo } from '../blitz/tankopedia';
import addPeriodSubCommands from './addPeriodSubCommands';
import addTankChoices from './addTankChoices';
import addUsernameChoices from './addUsernameChoices';
export default function addStatTypeSubCommandGroups(
export default async function addStatTypeSubCommandGroups(
option: SlashCommandBuilder,
) {
const awaitedTankopediaInfo = await tankopediaInfo;
return option
.addSubcommandGroup((option) =>
addPeriodSubCommands(option, (option) =>
option.addStringOption(addUsernameChoices),
)
.setName('player')
.setDescription("Player's statistics"),
.setDescription('Player statistics'),
)
.addSubcommandGroup((option) =>
addPeriodSubCommands(option, (option) =>
@@ -21,6 +24,58 @@ export default function addStatTypeSubCommandGroups(
.addStringOption(addUsernameChoices),
)
.setName('tank')
.setDescription("Tank's statistics"),
.setDescription('Tank statistics'),
)
.addSubcommandGroup((option) =>
addPeriodSubCommands(option, (option) =>
option
.addStringOption((option) => {
option
.setName('nation')
.setDescription('Nation')
.addChoices(
...Object.entries(awaitedTankopediaInfo.vehicle_nations).map(
([type, name]) => ({ name, value: type }),
),
);
return option;
})
.addStringOption((option) =>
option
.setName('tanktype')
.setDescription('Type')
.addChoices(
...Object.entries(awaitedTankopediaInfo.vehicle_types).map(
([type, name]) => ({
name: name.replace(' Tank', ''),
value: type,
}),
),
)
.setRequired(false),
)
.addIntegerOption((option) =>
option
.setName('tier')
.setDescription('Tier')
.setMinValue(1)
.setMaxValue(10)
.setRequired(false),
)
.addStringOption((option) =>
option
.setName('treetype')
.setDescription('Tech tree type')
.addChoices(
{ name: 'Tech Tree', value: 'techtree' },
{ name: 'Premium', value: 'premium' },
{ name: 'Collector', value: 'collector' },
)
.setRequired(false),
),
)
.setName('tanks')
.setDescription('Multiple tanks'),
);
}
+5 -9
View File
@@ -7,20 +7,16 @@ import { Period } from '../discord/addPeriodSubCommands';
export const PERIOD_NAMES: Record<Period, string> = {
today: "Today's statistics",
30: "30 days' statistics",
60: "60 days' statistics",
90: "90 days' statistics",
period: "Set number of days' statistics",
career: 'Career statistics',
custom: 'Custom period',
customperiod: 'Custom period',
};
export const EVOLUTION_PERIOD_NAMES: Record<Period, string> = {
today: "Today's evolution",
30: "30 days' evolution",
60: "60 days' evolution",
90: "90 days' evolution",
period: "Set number of days' evolution",
career: 'Career evolution',
custom: 'Custom period',
customperiod: 'Custom period',
};
export interface ResolvedPeriod {
@@ -40,7 +36,7 @@ export default function resolvePeriodFromCommand(
let end: number;
const period = interaction.options.getSubcommand() as Period;
if (period === 'custom') {
if (period === 'customperiod') {
const startRaw = interaction.options.getInteger('start')!;
const endRaw = interaction.options.getInteger('end')!;
const startMin = Math.min(startRaw, endRaw);
+67 -50
View File
@@ -54,22 +54,30 @@ export interface Registry {
inProduction: boolean;
}
export interface CommandRegistry<HandlesInteraction extends boolean = boolean>
extends Registry {
export type CommandRegistryRaw = Registry & {
inPublic: boolean;
inPreview?: boolean;
handlesInteraction?: HandlesInteraction;
command:
| SlashCommandBuilder
| SlashCommandSubcommandsOnlyBuilder
| Omit<SlashCommandBuilder, 'addSubcommand' | 'addSubcommandGroup'>;
handler: (
interaction: ChatInputCommandInteraction<CacheType>,
) => HandlesInteraction extends true ? void : InteractionReturnable;
autocomplete?: (interaction: AutocompleteInteraction<CacheType>) => void;
button?: (interaction: ButtonInteraction<CacheType>) => InteractionReturnable;
}
} & (
| {
handlesInteraction: true;
handler: (interaction: ChatInputCommandInteraction<CacheType>) => void;
}
| {
handlesInteraction?: false;
handler: (
interaction: ChatInputCommandInteraction<CacheType>,
) => InteractionReturnable;
}
);
export type CommandRegistry = CommandRegistryRaw | Promise<CommandRegistryRaw>;
const rest = new REST().setToken(secrets.DISCORD_TOKEN);
@@ -92,12 +100,19 @@ export const COMMANDS_RAW: CommandRegistry[] = [
statsCommand,
ratingsCommand,
];
export const commands: Record<string, CommandRegistry> = COMMANDS_RAW.reduce(
(accumulator, registry) => {
if (isDev()) registry.command.setDefaultMemberPermissions(0);
return { ...accumulator, [registry.command.name]: registry };
},
{},
export const commands = Promise.all(COMMANDS_RAW).then((rawCommands) =>
rawCommands.reduce<Record<string, CommandRegistryRaw>>(
(accumulator, registry) => {
if (isDev()) registry.command.setDefaultMemberPermissions(0);
return {
...accumulator,
[registry.command.name]: registry,
};
},
{},
),
);
export const guildCommands: RESTPostAPIChatInputApplicationCommandsJSONBody[] =
@@ -105,48 +120,50 @@ export const guildCommands: RESTPostAPIChatInputApplicationCommandsJSONBody[] =
export const publicCommands: RESTPostAPIChatInputApplicationCommandsJSONBody[] =
[];
Object.entries(commands).forEach(([, registry]) => {
if (isDev() ? registry.inDevelopment : registry.inProduction) {
const json = registry.command.toJSON();
commands.then((awaitedCommands) => {
Object.entries(awaitedCommands).forEach(([, registry]) => {
if (isDev() ? registry.inDevelopment : registry.inProduction) {
const json = registry.command.toJSON();
if (registry.inPublic) {
publicCommands.push(json);
} else {
guildCommands.push(json);
if (registry.inPublic) {
publicCommands.push(json);
} else {
guildCommands.push(json);
}
}
});
try {
console.log(`Refreshing ${publicCommands.length} public command(s).`);
rest
.put(Routes.applicationCommands(getClientId()), { body: publicCommands })
.then((publicData) => {
console.log(
`Successfully refreshed ${
(publicData as RESTPostAPIChatInputApplicationCommandsJSONBody[])
.length
} public command(s).`,
);
});
console.log(`Refreshing ${guildCommands.length} guild command(s).`);
rest
.put(
Routes.applicationGuildCommands(getClientId(), discord.tres_guild_id),
{ body: guildCommands },
)
.then((guildData) => {
console.log(
`Successfully refreshed ${
(guildData as unknown[]).length
} guild command(s).`,
);
});
} catch (error) {
console.error(error);
}
});
try {
console.log(`Refreshing ${publicCommands.length} public command(s).`);
rest
.put(Routes.applicationCommands(getClientId()), { body: publicCommands })
.then((publicData) => {
console.log(
`Successfully refreshed ${
(publicData as RESTPostAPIChatInputApplicationCommandsJSONBody[])
.length
} public command(s).`,
);
});
console.log(`Refreshing ${guildCommands.length} guild command(s).`);
rest
.put(
Routes.applicationGuildCommands(getClientId(), discord.tres_guild_id),
{ body: guildCommands },
)
.then((guildData) => {
console.log(
`Successfully refreshed ${
(guildData as unknown[]).length
} guild command(s).`,
);
});
} catch (error) {
console.error(error);
}
export default async function interactionCreate(
interaction: Interaction<CacheType>,
) {
+362 -589
View File
File diff suppressed because it is too large. Load diff