From 93ca2ba9fe691168e9561fc480fd6f521ee2025a Mon Sep 17 00:00:00 2001 From: skdhg <46562212+skdhg@users.noreply.github.com> Date: Sat, 25 Nov 2023 16:58:18 +0545 Subject: [PATCH 1/3] feat: lots of important stuff --- packages/commandkit/README.md | 2 +- packages/commandkit/bin/build.mjs | 15 +++--- packages/commandkit/bin/parse-env.mjs | 11 ++++- .../commandkit/src/components/ButtonKit.ts | 7 ++- .../command-handler/CommandHandler.ts | 27 +++++++---- .../src/handlers/command-handler/typings.ts | 12 ++++- .../command-handler/validations/devOnly.ts | 1 + .../validations/permissions.ts | 1 + .../handlers/event-handler/EventHandler.ts | 4 +- .../validation-handler/ValidationHandler.ts | 4 +- packages/commandkit/src/types/index.ts | 14 +++++- packages/commandkit/src/typings.ts | 27 ++++++++++- packages/commandkit/src/utils/clone.ts | 3 ++ .../tests/src/commands/misc/count.ts | 32 ++++++++----- .../tests/src/commands/misc/ping.ts | 47 +++++++++++++++++-- .../tests/src/validations/devOnly.ts | 3 +- 16 files changed, 164 insertions(+), 46 deletions(-) create mode 100644 packages/commandkit/src/utils/clone.ts diff --git a/packages/commandkit/README.md b/packages/commandkit/README.md index 9ee1c18..4c376e9 100644 --- a/packages/commandkit/README.md +++ b/packages/commandkit/README.md @@ -19,7 +19,7 @@ CommandKit is a library that makes it easy to handle commands and events in your - Automatic command registration, edits, and deletion 🤖 - Supports multiple development servers 🤝 - Supports multiple users as bot developers 👥 -- Object oriented 💻 +- User friendly CLI 🖥️ ## Documentation diff --git a/packages/commandkit/bin/build.mjs b/packages/commandkit/bin/build.mjs index f394c0d..0100e79 100644 --- a/packages/commandkit/bin/build.mjs +++ b/packages/commandkit/bin/build.mjs @@ -39,7 +39,7 @@ export async function bootstrapProductionBuild(config) { entry: [src, '!dist', '!.commandkit', `!${outDir}`], }); - if (antiCrash) await injectAntiCrash(outDir, main); + await injectShims(outDir, main, antiCrash); status.succeed( Colors.green(`Build completed in ${(performance.now() - start).toFixed(2)}ms!`), @@ -55,9 +55,10 @@ export async function bootstrapProductionBuild(config) { } } -function injectAntiCrash(outDir, main) { +async function injectShims(outDir, main, antiCrash) { const path = join(process.cwd(), outDir, main); - const snippet = [ + + const antiCrashScript = antiCrash ? [ '\n\n// --- CommandKit Anti-Crash Monitor ---', ';(()=>{', " 'use strict';", @@ -66,7 +67,7 @@ function injectAntiCrash(outDir, main) { ' // But it exists here due to compatibility reasons with discord bot ecosystem.', " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", ' if (!process.eventNames().includes(e1)) // skip if it is already handled', - ' process.on(e1, (e, o) => {', + ' process.on(e1, (e) => {', ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', ' })', ' if (!process.eventNames().includes(e2)) // skip if it is already handled', @@ -75,7 +76,9 @@ function injectAntiCrash(outDir, main) { ' });', '})();', '// --- CommandKit Anti-Crash Monitor ---\n', - ].join('\n'); + ].join('\n') : ''; + + const finalScript = [antiCrashScript].join('\n'); - return appendFile(path, snippet); + return appendFile(path, finalScript); } diff --git a/packages/commandkit/bin/parse-env.mjs b/packages/commandkit/bin/parse-env.mjs index abe5add..451ae5d 100644 --- a/packages/commandkit/bin/parse-env.mjs +++ b/packages/commandkit/bin/parse-env.mjs @@ -15,6 +15,15 @@ const VALUE_PREFIXES = { DATE: 'DATE::', }; +function catcher(fn) { + try { + fn(); + return true; + } catch { + return false; + } +} + export function parseEnv(src) { for (const key in src) { const value = src[key]; @@ -22,7 +31,7 @@ export function parseEnv(src) { if (typeof value !== 'string') continue; if (value.startsWith(VALUE_PREFIXES.JSON)) { - src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, '')); + catcher(() => src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, ''))); continue; } diff --git a/packages/commandkit/src/components/ButtonKit.ts b/packages/commandkit/src/components/ButtonKit.ts index bae9636..6eddc1a 100644 --- a/packages/commandkit/src/components/ButtonKit.ts +++ b/packages/commandkit/src/components/ButtonKit.ts @@ -10,8 +10,12 @@ import { ComponentType, } from 'discord.js'; +/** + * The handler to run when a button is clicked. This handler is called with the interaction as the first argument. + * If the first argument is null, it means that the interaction collector has been destroyed. + */ export type CommandKitButtonBuilderInteractionCollectorDispatch = ( - interaction: ButtonInteraction, + interaction: ButtonInteraction | null, ) => Awaitable; export type CommandKitButtonBuilderInteractionCollectorDispatchContextData = { @@ -133,6 +137,7 @@ export class ButtonKit extends ButtonBuilder { } #destroyCollector() { + this.#onClickHandler?.(null); this.#collector?.stop('end'); this.#collector?.removeAllListeners(); this.#collector = null; diff --git a/packages/commandkit/src/handlers/command-handler/CommandHandler.ts b/packages/commandkit/src/handlers/command-handler/CommandHandler.ts index 84c2b8f..7ce91e2 100644 --- a/packages/commandkit/src/handlers/command-handler/CommandHandler.ts +++ b/packages/commandkit/src/handlers/command-handler/CommandHandler.ts @@ -8,10 +8,7 @@ import loadCommandsWithRest from './functions/loadCommandsWithRest'; import registerCommands from './functions/registerCommands'; import builtInValidations from './validations'; import colors from '../../utils/colors'; - -import rdfc from 'rfdc'; - -const clone = rdfc(); +import { clone } from '../../utils/clone'; /** * A handler for client application commands. @@ -80,7 +77,7 @@ export class CommandHandler { for (const commandFilePath of commandFilePaths) { const modulePath = toFileURL(commandFilePath); - let importedObj = await import(`${modulePath}?t=${Date.now()}`); + const importedObj = await import(`${modulePath}?t=${Date.now()}`); let commandObj: CommandFileObject = clone(importedObj); // Make commandObj extensible // If it's CommonJS, invalidate the import cache @@ -161,7 +158,14 @@ export class CommandHandler { handleCommands() { this.#data.client.on('interactionCreate', async (interaction) => { - if (!interaction.isChatInputCommand() && !interaction.isContextMenuCommand()) return; + if ( + !interaction.isChatInputCommand() && + !interaction.isContextMenuCommand() && + !interaction.isAutocomplete() + ) + return; + + const isAutocomplete = interaction.isAutocomplete(); const targetCommand = this.#data.commands.find( (cmd) => cmd.data.name === interaction.commandName, @@ -169,7 +173,10 @@ export class CommandHandler { if (!targetCommand) return; - const { data, options, run, ...rest } = targetCommand; + const { data, options, run, autocompleteRun, ...rest } = targetCommand; + + // skip if autocomplete handler is not defined + if (isAutocomplete && !autocompleteRun) return; const commandObj = { data: targetCommand.data, @@ -217,11 +224,13 @@ export class CommandHandler { if (!canRun) return; - targetCommand.run({ + const context = { interaction, client: this.#data.client, handler: this.#data.commandkitInstance, - }); + }; + + await targetCommand[isAutocomplete ? 'autocompleteRun' : 'run']!(context); }); } diff --git a/packages/commandkit/src/handlers/command-handler/typings.ts b/packages/commandkit/src/handlers/command-handler/typings.ts index ef0be40..34de53f 100644 --- a/packages/commandkit/src/handlers/command-handler/typings.ts +++ b/packages/commandkit/src/handlers/command-handler/typings.ts @@ -1,4 +1,9 @@ -import { ChatInputCommandInteraction, Client, ContextMenuCommandInteraction } from 'discord.js'; +import { + AutocompleteInteraction, + ChatInputCommandInteraction, + Client, + ContextMenuCommandInteraction, +} from 'discord.js'; import { CommandKit } from '../../CommandKit'; import { CommandFileObject } from '../../typings'; import { ValidationHandler } from '../validation-handler/ValidationHandler'; @@ -86,7 +91,10 @@ export interface BuiltInValidationParams { /** * The interaction of the target command. */ - interaction: ChatInputCommandInteraction | ContextMenuCommandInteraction; + interaction: + | ChatInputCommandInteraction + | ContextMenuCommandInteraction + | AutocompleteInteraction; /** * The command handler's data. diff --git a/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts b/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts index 1f6d9ec..5321887 100644 --- a/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts +++ b/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts @@ -1,6 +1,7 @@ import { BuiltInValidationParams } from '../typings'; export default function ({ interaction, targetCommand, handlerData }: BuiltInValidationParams) { + if (interaction.isAutocomplete()) return; if (targetCommand.options?.devOnly) { if (interaction.inGuild() && !handlerData.devGuildIds.includes(interaction.guildId)) { interaction.reply({ diff --git a/packages/commandkit/src/handlers/command-handler/validations/permissions.ts b/packages/commandkit/src/handlers/command-handler/validations/permissions.ts index c5946b1..3d89a64 100644 --- a/packages/commandkit/src/handlers/command-handler/validations/permissions.ts +++ b/packages/commandkit/src/handlers/command-handler/validations/permissions.ts @@ -2,6 +2,7 @@ import type { BuiltInValidationParams } from '../typings'; import { EmbedBuilder } from 'discord.js'; export default function ({ interaction, targetCommand }: BuiltInValidationParams) { + if (interaction.isAutocomplete()) return; const userPermissions = interaction.memberPermissions; let userPermissionsRequired = targetCommand.options?.userPermissions; let missingUserPermissions: string[] = []; diff --git a/packages/commandkit/src/handlers/event-handler/EventHandler.ts b/packages/commandkit/src/handlers/event-handler/EventHandler.ts index 198e20e..c0f8e92 100644 --- a/packages/commandkit/src/handlers/event-handler/EventHandler.ts +++ b/packages/commandkit/src/handlers/event-handler/EventHandler.ts @@ -3,9 +3,7 @@ import type { CommandHandler } from '../command-handler/CommandHandler'; import { getFilePaths, getFolderPaths } from '../../utils/get-paths'; import { toFileURL } from '../../utils/resolve-file-url'; import colors from '../../utils/colors'; -import rdfc from 'rfdc'; - -const clone = rdfc(); +import { clone } from '../../utils/clone'; /** * A handler for client events. diff --git a/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts b/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts index 4e37b49..350aae6 100644 --- a/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts +++ b/packages/commandkit/src/handlers/validation-handler/ValidationHandler.ts @@ -2,9 +2,7 @@ import type { ValidationHandlerData, ValidationHandlerOptions } from './typings' import { toFileURL } from '../../utils/resolve-file-url'; import { getFilePaths } from '../../utils/get-paths'; import colors from '../../utils/colors'; -import rdfc from 'rfdc'; - -const clone = rdfc(); +import { clone } from '../../utils/clone'; /** * A handler for command validations. diff --git a/packages/commandkit/src/types/index.ts b/packages/commandkit/src/types/index.ts index c5d1e0e..2cfa9e5 100644 --- a/packages/commandkit/src/types/index.ts +++ b/packages/commandkit/src/types/index.ts @@ -6,6 +6,7 @@ import { type ChatInputCommandInteraction, type PermissionsString, type Client, + AutocompleteInteraction, } from 'discord.js'; import type { CommandKit } from '../CommandKit'; @@ -20,7 +21,8 @@ export interface CommandProps { | ChatInputCommandInteraction | ContextMenuCommandInteraction | UserContextMenuCommandInteraction - | MessageContextMenuCommandInteraction; + | MessageContextMenuCommandInteraction + | AutocompleteInteraction; /** * The Discord.js client object that CommandKit is handling. @@ -33,6 +35,16 @@ export interface CommandProps { handler: CommandKit; } +/** + * Props for autocomplete command run functions. + */ +export interface AutocompleteCommandProps extends CommandProps { + /** + * The current autocomplete command interaction object. + */ + interaction: AutocompleteInteraction; +} + /** * Props for slash (chat input) command run functions. */ diff --git a/packages/commandkit/src/typings.ts b/packages/commandkit/src/typings.ts index 2b36e35..11e4ef3 100644 --- a/packages/commandkit/src/typings.ts +++ b/packages/commandkit/src/typings.ts @@ -1,7 +1,7 @@ // This types file is for development // For exported types use ./types/index.ts -import type { Client, Interaction } from 'discord.js'; +import type { AutocompleteInteraction, CacheType, Client, Interaction } from 'discord.js'; import type { CommandData, CommandKit, CommandOptions, ReloadType } from './index'; import type { CommandHandler, EventHandler, ValidationHandler } from './handlers'; @@ -64,13 +64,36 @@ export interface CommandKitData extends CommandKitOptions { validationHandler?: ValidationHandler; } +/** + * Represents a command context. + */ +export interface CommandContext { + /** + * The interaction that triggered this command. + */ + interaction: Interaction; + /** + * The client that instantiated this command. + */ + client: Client; + /** + * The command data. + */ + handler: CommandKit; +} + /** * Represents a command file. */ export interface CommandFileObject { data: CommandData; options?: CommandOptions; - run: ({}: { interaction: Interaction; client: Client; handler: CommandKit }) => void; + run: ( + ctx: CommandContext, + ) => Awaited; + autocompleteRun?: ( + ctx: CommandContext, + ) => Awaited; filePath: string; category: string | null; [key: string]: any; diff --git a/packages/commandkit/src/utils/clone.ts b/packages/commandkit/src/utils/clone.ts new file mode 100644 index 0000000..ec31a9e --- /dev/null +++ b/packages/commandkit/src/utils/clone.ts @@ -0,0 +1,3 @@ +import rfdc from 'rfdc'; + +export const clone = rfdc(); diff --git a/packages/commandkit/tests/src/commands/misc/count.ts b/packages/commandkit/tests/src/commands/misc/count.ts index fe41997..0b211a6 100644 --- a/packages/commandkit/tests/src/commands/misc/count.ts +++ b/packages/commandkit/tests/src/commands/misc/count.ts @@ -57,37 +57,47 @@ export async function run({ interaction }: SlashCommandProps) { inter?.update(`Count is ${value}`); }); + const disposeButtons = async (interaction: ButtonInteraction | null = null) => { + const disposed = row.setComponents( + row.components.map((button) => button.onClick(null).setDisabled(true)), + ); + + // Dispose the count's subscribers + disposeCountSubscribers(); + + const data = { + content: 'Finished counting!', + components: [disposed], + }; + + if (interaction) await interaction.update(data); + else await message.edit(data); + }; + // prettier-ignore dec.onClick((interaction) => { + if (!interaction) return disposeButtons(); inter = interaction; setCount((prev) => prev - 1); }, { message }); // prettier-ignore reset.onClick((interaction) => { + if (!interaction) return disposeButtons(); inter = interaction; setCount(0); }, { message }); // prettier-ignore inc.onClick((interaction) => { + if (!interaction) return disposeButtons(); inter = interaction; setCount((prev) => prev + 1); }, { message }); // prettier-ignore trash.onClick(async (interaction) => { - const disposed = row.setComponents( - row.components.map((button) => button.onClick(null).setDisabled(true)), - ); - - // Dispose the count's subscribers - disposeCountSubscribers(); - - await interaction.update({ - content: 'Finished counting!', - components: [disposed], - }); + disposeButtons(interaction); }, { message }); } diff --git a/packages/commandkit/tests/src/commands/misc/ping.ts b/packages/commandkit/tests/src/commands/misc/ping.ts index 982d3d7..40d11c0 100644 --- a/packages/commandkit/tests/src/commands/misc/ping.ts +++ b/packages/commandkit/tests/src/commands/misc/ping.ts @@ -1,11 +1,40 @@ -import { ActionRowBuilder, ButtonStyle } from 'discord.js'; -import { SlashCommandProps, CommandOptions, CommandData, ButtonKit } from '../../../../src/index'; +import { ActionRowBuilder, ApplicationCommandOptionType, ButtonStyle } from 'discord.js'; +import { + SlashCommandProps, + CommandOptions, + CommandData, + ButtonKit, + AutocompleteCommandProps, +} from '../../../../src/index'; export const data: CommandData = { name: 'ping', description: 'Pong!', + options: [ + { + name: 'test', + description: 'Test option for autocomplete', + autocomplete: true, + type: ApplicationCommandOptionType.String, + required: false, + }, + ], }; +const tests = Array.from({ length: 10 }, (_, i) => ({ + name: `Test ${i + 1}`, + value: `${i}_test`, +})); + +export async function autocompleteRun({ interaction }: AutocompleteCommandProps) { + const arg = interaction.options.getString('test', false); + if (!arg) return interaction.respond(tests); + + const filtered = tests.filter((test) => test.name.toLowerCase().includes(arg.toLowerCase())); + + interaction.respond(filtered); +} + export async function run({ interaction, client }: SlashCommandProps) { if (!interaction.channel) return; @@ -23,8 +52,16 @@ export async function run({ interaction, client }: SlashCommandProps) { }); button.onClick( - (interaction) => { - interaction.reply({ + (inter) => { + if (!inter) { + button.setDisabled(true); + message.edit({ + components: [row], + }); + return; + } + + inter.reply({ content: 'You clicked the ping button!', ephemeral: true, }); @@ -32,7 +69,7 @@ export async function run({ interaction, client }: SlashCommandProps) { { message, time: 10_000, autoReset: true }, ); - interaction.reply(`:ping_pong: Pong! \`${client.ws.ping}ms\``); + // interaction.reply(`:ping_pong: Pong! \`${client.ws.ping}ms\``); } export const options: CommandOptions = { diff --git a/packages/commandkit/tests/src/validations/devOnly.ts b/packages/commandkit/tests/src/validations/devOnly.ts index 30c6207..014edf5 100644 --- a/packages/commandkit/tests/src/validations/devOnly.ts +++ b/packages/commandkit/tests/src/validations/devOnly.ts @@ -1,8 +1,9 @@ import type { ValidationFunctionProps } from '../../../src'; export default function ({ interaction, commandObj, handler }: ValidationFunctionProps) { + if (interaction.isAutocomplete()) return; if (commandObj.data.name === 'ping') { interaction.reply('blocked...'); - return true; + return false; } } From 075ad8e483c287acf19310b250f190a09ba2bc5b Mon Sep 17 00:00:00 2001 From: skdhg <46562212+skdhg@users.noreply.github.com> Date: Sat, 25 Nov 2023 17:05:31 +0545 Subject: [PATCH 2/3] types: explicit import --- .../src/handlers/command-handler/typings.ts | 8 ++++---- .../command-handler/validations/devOnly.ts | 2 +- packages/commandkit/src/types/index.ts | 16 ++++++++-------- packages/commandkit/src/typings.ts | 2 +- .../commandkit/tests/src/validations/devOnly.ts | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/commandkit/src/handlers/command-handler/typings.ts b/packages/commandkit/src/handlers/command-handler/typings.ts index 34de53f..336d231 100644 --- a/packages/commandkit/src/handlers/command-handler/typings.ts +++ b/packages/commandkit/src/handlers/command-handler/typings.ts @@ -1,12 +1,12 @@ -import { +import type { AutocompleteInteraction, ChatInputCommandInteraction, Client, ContextMenuCommandInteraction, } from 'discord.js'; -import { CommandKit } from '../../CommandKit'; -import { CommandFileObject } from '../../typings'; -import { ValidationHandler } from '../validation-handler/ValidationHandler'; +import type { CommandKit } from '../../CommandKit'; +import type { CommandFileObject } from '../../typings'; +import type { ValidationHandler } from '../validation-handler/ValidationHandler'; /** * Command handler options. diff --git a/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts b/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts index 5321887..cb043af 100644 --- a/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts +++ b/packages/commandkit/src/handlers/command-handler/validations/devOnly.ts @@ -1,4 +1,4 @@ -import { BuiltInValidationParams } from '../typings'; +import type { BuiltInValidationParams } from '../typings'; export default function ({ interaction, targetCommand, handlerData }: BuiltInValidationParams) { if (interaction.isAutocomplete()) return; diff --git a/packages/commandkit/src/types/index.ts b/packages/commandkit/src/types/index.ts index 2cfa9e5..5bda5b0 100644 --- a/packages/commandkit/src/types/index.ts +++ b/packages/commandkit/src/types/index.ts @@ -1,11 +1,11 @@ -import { - type RESTPostAPIApplicationCommandsJSONBody, - type MessageContextMenuCommandInteraction, - type UserContextMenuCommandInteraction, - type ContextMenuCommandInteraction, - type ChatInputCommandInteraction, - type PermissionsString, - type Client, +import type { + RESTPostAPIApplicationCommandsJSONBody, + MessageContextMenuCommandInteraction, + UserContextMenuCommandInteraction, + ContextMenuCommandInteraction, + ChatInputCommandInteraction, + PermissionsString, + Client, AutocompleteInteraction, } from 'discord.js'; import type { CommandKit } from '../CommandKit'; diff --git a/packages/commandkit/src/typings.ts b/packages/commandkit/src/typings.ts index 11e4ef3..e2d96a6 100644 --- a/packages/commandkit/src/typings.ts +++ b/packages/commandkit/src/typings.ts @@ -1,7 +1,7 @@ // This types file is for development // For exported types use ./types/index.ts -import type { AutocompleteInteraction, CacheType, Client, Interaction } from 'discord.js'; +import type { CacheType, Client, Interaction } from 'discord.js'; import type { CommandData, CommandKit, CommandOptions, ReloadType } from './index'; import type { CommandHandler, EventHandler, ValidationHandler } from './handlers'; diff --git a/packages/commandkit/tests/src/validations/devOnly.ts b/packages/commandkit/tests/src/validations/devOnly.ts index 014edf5..a5cb2fa 100644 --- a/packages/commandkit/tests/src/validations/devOnly.ts +++ b/packages/commandkit/tests/src/validations/devOnly.ts @@ -4,6 +4,6 @@ export default function ({ interaction, commandObj, handler }: ValidationFunctio if (interaction.isAutocomplete()) return; if (commandObj.data.name === 'ping') { interaction.reply('blocked...'); - return false; + return true; } } From d1120fdee12a547a9c5afa8a5110524b1d5c0b5f Mon Sep 17 00:00:00 2001 From: skdhg <46562212+skdhg@users.noreply.github.com> Date: Sat, 25 Nov 2023 17:06:50 +0545 Subject: [PATCH 3/3] chore: prettier --- packages/commandkit/bin/build.mjs | 40 ++++++++++++++------------- packages/commandkit/bin/parse-env.mjs | 2 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/commandkit/bin/build.mjs b/packages/commandkit/bin/build.mjs index 0100e79..3997599 100644 --- a/packages/commandkit/bin/build.mjs +++ b/packages/commandkit/bin/build.mjs @@ -58,25 +58,27 @@ export async function bootstrapProductionBuild(config) { async function injectShims(outDir, main, antiCrash) { const path = join(process.cwd(), outDir, main); - const antiCrashScript = antiCrash ? [ - '\n\n// --- CommandKit Anti-Crash Monitor ---', - ';(()=>{', - " 'use strict';", - " // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process", - ' // instead of using it as a means to resume operation.', - ' // But it exists here due to compatibility reasons with discord bot ecosystem.', - " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", - ' if (!process.eventNames().includes(e1)) // skip if it is already handled', - ' process.on(e1, (e) => {', - ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', - ' })', - ' if (!process.eventNames().includes(e2)) // skip if it is already handled', - ' process.on(e2, (r) => {', - ' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));', - ' });', - '})();', - '// --- CommandKit Anti-Crash Monitor ---\n', - ].join('\n') : ''; + const antiCrashScript = antiCrash + ? [ + '\n\n// --- CommandKit Anti-Crash Monitor ---', + ';(()=>{', + " 'use strict';", + " // 'uncaughtException' event is supposed to be used to perform synchronous cleanup before shutting down the process", + ' // instead of using it as a means to resume operation.', + ' // But it exists here due to compatibility reasons with discord bot ecosystem.', + " const p = (t) => `\\x1b[33m${t}\\x1b[0m`, b = '[CommandKit Anti-Crash Monitor]', l = console.log, e1 = 'uncaughtException', e2 = 'unhandledRejection';", + ' if (!process.eventNames().includes(e1)) // skip if it is already handled', + ' process.on(e1, (e) => {', + ' l(p(`${b} Uncaught Exception`)); l(p(b), p(e.stack || e));', + ' })', + ' if (!process.eventNames().includes(e2)) // skip if it is already handled', + ' process.on(e2, (r) => {', + ' l(p(`${b} Unhandled promise rejection`)); l(p(`${b} ${r.stack || r}`));', + ' });', + '})();', + '// --- CommandKit Anti-Crash Monitor ---\n', + ].join('\n') + : ''; const finalScript = [antiCrashScript].join('\n'); diff --git a/packages/commandkit/bin/parse-env.mjs b/packages/commandkit/bin/parse-env.mjs index 451ae5d..371b7f9 100644 --- a/packages/commandkit/bin/parse-env.mjs +++ b/packages/commandkit/bin/parse-env.mjs @@ -31,7 +31,7 @@ export function parseEnv(src) { if (typeof value !== 'string') continue; if (value.startsWith(VALUE_PREFIXES.JSON)) { - catcher(() => src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, ''))); + catcher(() => (src[key] = JSON.parse(value.replace(VALUE_PREFIXES.JSON, '')))); continue; }