discord-bot-shared 0.16.0 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +3 -1
- package/dist/bot.js.map +1 -1
- package/dist/command-manager.d.ts +5 -3
- package/dist/command-manager.d.ts.map +1 -1
- package/dist/command-manager.js +17 -16
- package/dist/command-manager.js.map +1 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +2 -0
- package/dist/components.js.map +1 -1
- package/dist/event-manager.d.ts +4 -4
- package/dist/event-manager.d.ts.map +1 -1
- package/dist/event-manager.js +10 -7
- package/dist/event-manager.js.map +1 -1
- package/dist/util.js +4 -2
- package/dist/util.js.map +1 -1
- package/package.json +38 -26
package/LICENSE
CHANGED
package/dist/bot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bot.d.ts","names":[],"sources":["../src/bot.ts"],"
|
|
1
|
+
{"version":3,"file":"bot.d.ts","names":[],"sources":["../src/bot.ts"],"mappings":";;;;;UAQU,UAAA;EACR,aAAA;EACA,KAAA;EACA,aAAA,EAAe,aAAa;AAAA;AAAA,UAGb,cAAA;EACf,aAAA;EACA,KAAA;EACA,MAAA,EAAQ,MAAA;EACR,IAAA,EAAM,IAAI;AAAA;AAAA,cAGC,GAAA;EAAA;WAGK,QAAA,EAAU,cAAA;EAAA,SACV,MAAA,EAAQ,YAAA;cAEL,OAAA,EAAS,UAAA;EAYf,KAAA,IAAS,OAAA;AAAA"}
|
package/dist/bot.js
CHANGED
|
@@ -2,6 +2,7 @@ import { CommandManager } from "./command-manager.js";
|
|
|
2
2
|
import { EventManager } from "./event-manager.js";
|
|
3
3
|
import { Client, Events, REST } from "discord.js";
|
|
4
4
|
import { attempt, isErr } from "ts-explicit-errors";
|
|
5
|
+
//#region src/bot.ts
|
|
5
6
|
var Bot = class {
|
|
6
7
|
#discord;
|
|
7
8
|
commands;
|
|
@@ -22,10 +23,11 @@ var Bot = class {
|
|
|
22
23
|
});
|
|
23
24
|
this.commands._listen();
|
|
24
25
|
this.events._listen();
|
|
25
|
-
const loginResult = await attempt(() => this.#discord.client.login(this.#discord.token));
|
|
26
|
+
const loginResult = await attempt(async () => this.#discord.client.login(this.#discord.token));
|
|
26
27
|
if (isErr(loginResult)) console.error(`failed to login: ${loginResult.messageChain}`);
|
|
27
28
|
}
|
|
28
29
|
};
|
|
30
|
+
//#endregion
|
|
29
31
|
export { Bot };
|
|
30
32
|
|
|
31
33
|
//# sourceMappingURL=bot.js.map
|
package/dist/bot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bot.js","names":["#discord"],"sources":["../src/bot.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"bot.js","names":["#discord"],"sources":["../src/bot.ts"],"sourcesContent":["// oxlint-disable no-underscore-dangle\nimport type { ClientOptions } from \"discord.js\"\nimport { Client, Events, REST } from \"discord.js\"\nimport { attempt, isErr } from \"ts-explicit-errors\"\n\nimport { CommandManager } from \"#/command-manager.ts\"\nimport { EventManager } from \"#/event-manager.ts\"\n\ninterface BotOptions {\n applicationId: string\n token: string\n clientOptions: ClientOptions\n}\n\nexport interface DiscordContext {\n applicationId: string\n token: string\n client: Client\n rest: REST\n}\n\nexport class Bot {\n readonly #discord: DiscordContext\n\n public readonly commands: CommandManager\n public readonly events: EventManager\n\n public constructor(options: BotOptions) {\n this.#discord = {\n applicationId: options.applicationId,\n token: options.token,\n client: new Client(options.clientOptions),\n rest: new REST().setToken(options.token),\n }\n\n this.commands = new CommandManager(this.#discord)\n this.events = new EventManager(this.#discord)\n }\n\n public async login(): Promise<void> {\n this.#discord.client.once(Events.ClientReady, (readyClient) => {\n console.log(`Client is ready. Logged in as '${readyClient.user.tag}'.`)\n })\n\n this.commands._listen()\n this.events._listen()\n\n const loginResult = await attempt(async () => this.#discord.client.login(this.#discord.token))\n if (isErr(loginResult)) console.error(`failed to login: ${loginResult.messageChain}`)\n }\n}\n"],"mappings":";;;;;AAqBA,IAAa,MAAb,MAAiB;CACf;CAEA;CACA;CAEA,YAAmB,SAAqB;EACtC,KAAKA,WAAW;GACd,eAAe,QAAQ;GACvB,OAAO,QAAQ;GACf,QAAQ,IAAI,OAAO,QAAQ,aAAa;GACxC,MAAM,IAAI,KAAK,CAAC,CAAC,SAAS,QAAQ,KAAK;EACzC;EAEA,KAAK,WAAW,IAAI,eAAe,KAAKA,QAAQ;EAChD,KAAK,SAAS,IAAI,aAAa,KAAKA,QAAQ;CAC9C;CAEA,MAAa,QAAuB;EAClC,KAAKA,SAAS,OAAO,KAAK,OAAO,cAAc,gBAAgB;GAC7D,QAAQ,IAAI,kCAAkC,YAAY,KAAK,IAAI,GAAG;EACxE,CAAC;EAED,KAAK,SAAS,QAAQ;EACtB,KAAK,OAAO,QAAQ;EAEpB,MAAM,cAAc,MAAM,QAAQ,YAAY,KAAKA,SAAS,OAAO,MAAM,KAAKA,SAAS,KAAK,CAAC;EAC7F,IAAI,MAAM,WAAW,GAAG,QAAQ,MAAM,oBAAoB,YAAY,cAAc;CACtF;AACF"}
|
|
@@ -8,10 +8,12 @@ interface Command {
|
|
|
8
8
|
command: SlashCommandBuilder | SlashCommandOptionsOnlyBuilder;
|
|
9
9
|
run: CommandRunFn;
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
success:
|
|
11
|
+
type CommandHookResult = {
|
|
12
|
+
success: true;
|
|
13
|
+
} | {
|
|
14
|
+
success: false;
|
|
13
15
|
message?: string;
|
|
14
|
-
}
|
|
16
|
+
};
|
|
15
17
|
type CommandHook = (interaction: ChatInputCommandInteraction<"cached">) => CommandHookResult | Promise<CommandHookResult>;
|
|
16
18
|
declare class CommandManager {
|
|
17
19
|
#private;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-manager.d.ts","names":[],"sources":["../src/command-manager.ts"],"
|
|
1
|
+
{"version":3,"file":"command-manager.d.ts","names":[],"sources":["../src/command-manager.ts"],"mappings":";;;;KAcY,YAAA,IAAgB,WAAA,EAAa,2BAAA,sBAAiD,OAAO;AAAA,UAEhF,OAAA;EACf,aAAA;EACA,OAAA,EAAS,mBAAA,GAAsB,8BAAA;EAC/B,GAAA,EAAK,YAAA;AAAA;AAAA,KAGF,iBAAA;EAEC,OAAA;AAAA;EAGA,OAAA;EACA,OAAA;AAAA;AAAA,KAGM,WAAA,IACV,WAAA,EAAa,2BAAA,eACV,iBAAA,GAAoB,OAAA,CAAQ,iBAAA;AAAA,cAEpB,cAAA;EAAA;cAKQ,OAAA,EAAS,cAAA;EAAA,QAIpB,iBAAA;EAAA,QAIM,OAAA;EAQP,GAAA,CAAI,OAAA,EAAS,OAAA;EAIb,oBAAA,CAAqB,WAAA,EAAa,WAAA;EAI5B,QAAA,IAAY,OAAA;EAWZ,UAAA,IAAc,OAAA;EAWd,aAAA,IAAa,OAAA;EAmCb,eAAA,IAAmB,OAAA;EAiCzB,OAAA;EAAA,eAuEc,UAAA;EAAA,eAaA,qBAAA;AAAA"}
|
package/dist/command-manager.js
CHANGED
|
@@ -2,6 +2,7 @@ import { components } from "./components.js";
|
|
|
2
2
|
import { handleCallback } from "./util.js";
|
|
3
3
|
import { Collection, Events, MessageFlags, Routes } from "discord.js";
|
|
4
4
|
import { CtxError, attempt, err, filterMap, isErr } from "ts-explicit-errors";
|
|
5
|
+
//#region src/command-manager.ts
|
|
5
6
|
var CommandManager = class CommandManager {
|
|
6
7
|
#commands = new Collection();
|
|
7
8
|
#globalCommandHook;
|
|
@@ -14,7 +15,7 @@ var CommandManager = class CommandManager {
|
|
|
14
15
|
}
|
|
15
16
|
async onReady(fn) {
|
|
16
17
|
if (this.#discord.client.isReady()) await handleCallback(fn);
|
|
17
|
-
else this.#discord.client.once(Events.ClientReady,
|
|
18
|
+
else this.#discord.client.once(Events.ClientReady, () => void handleCallback(fn));
|
|
18
19
|
}
|
|
19
20
|
add(command) {
|
|
20
21
|
this.#commands.set(command.command.name, command);
|
|
@@ -40,7 +41,7 @@ var CommandManager = class CommandManager {
|
|
|
40
41
|
}
|
|
41
42
|
async guildRegister() {
|
|
42
43
|
const registerGuildCommands = async () => {
|
|
43
|
-
const guilds = await attempt(() => this.#discord.client.guilds.fetch());
|
|
44
|
+
const guilds = await attempt(async () => this.#discord.client.guilds.fetch());
|
|
44
45
|
if (isErr(guilds)) return err("failed to fetch guilds", guilds);
|
|
45
46
|
const commandPayload = this.getCommandPayload();
|
|
46
47
|
const { errors } = await filterMap(guilds.values(), async (guild) => {
|
|
@@ -60,7 +61,7 @@ var CommandManager = class CommandManager {
|
|
|
60
61
|
}
|
|
61
62
|
async guildUnregister() {
|
|
62
63
|
const unregisterGuildCommands = async () => {
|
|
63
|
-
const guilds = await attempt(() => this.#discord.client.guilds.fetch());
|
|
64
|
+
const guilds = await attempt(async () => this.#discord.client.guilds.fetch());
|
|
64
65
|
if (isErr(guilds)) return err("failed to fetch guilds", guilds);
|
|
65
66
|
const { errors } = await filterMap(guilds.values(), async (guild) => {
|
|
66
67
|
const registerResult = await attempt(async () => {
|
|
@@ -82,27 +83,26 @@ var CommandManager = class CommandManager {
|
|
|
82
83
|
if (!interaction.isChatInputCommand()) return;
|
|
83
84
|
if (!interaction.guildId) return;
|
|
84
85
|
const guild = await interaction.client.guilds.fetch(interaction.guildId);
|
|
85
|
-
if (isErr(guild)) return
|
|
86
|
-
if (!interaction.inCachedGuild()) return
|
|
86
|
+
if (isErr(guild)) return CommandManager.interactionErrorReply(interaction, err(`failed to fetch guild with id '${interaction.guildId}'`, guild));
|
|
87
|
+
if (!interaction.inCachedGuild()) return CommandManager.interactionErrorReply(interaction, "Guild is not cached. Try again.");
|
|
87
88
|
const command = this.#commands.get(interaction.commandName);
|
|
88
|
-
if (!command) return
|
|
89
|
+
if (!command) return CommandManager.interactionErrorReply(interaction, err(`failed to get command with name '${interaction.commandName}'`, void 0));
|
|
89
90
|
const hasRequiredRole = await CommandManager.checkRoles(command, interaction);
|
|
90
|
-
if (isErr(hasRequiredRole)) return
|
|
91
|
-
if (!hasRequiredRole) return
|
|
92
|
-
const globalCommandHookResult = await attempt(() => this.#globalCommandHook ? this.#globalCommandHook(interaction) : { success: true });
|
|
93
|
-
if (isErr(globalCommandHookResult)) return
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (isErr(commandRunResult)) return await CommandManager.interactionErrorReply(interaction, err(`failed to run command \`${command.command.name}\``, commandRunResult));
|
|
91
|
+
if (isErr(hasRequiredRole)) return CommandManager.interactionErrorReply(interaction, err("failed to check roles", hasRequiredRole));
|
|
92
|
+
if (!hasRequiredRole) return CommandManager.interactionErrorReply(interaction, "You do not have one of the required roles to run this command.", "warn");
|
|
93
|
+
const globalCommandHookResult = await attempt(async () => this.#globalCommandHook ? this.#globalCommandHook(interaction) : { success: true });
|
|
94
|
+
if (isErr(globalCommandHookResult)) return CommandManager.interactionErrorReply(interaction, err("failed to run global command hook", globalCommandHookResult));
|
|
95
|
+
if (!globalCommandHookResult.success) return CommandManager.interactionErrorReply(interaction, globalCommandHookResult.message ?? "The global command hook did not succeed.", "warn");
|
|
96
|
+
const commandRunResult = await attempt(async () => command.run(interaction));
|
|
97
|
+
if (isErr(commandRunResult)) return CommandManager.interactionErrorReply(interaction, err(`failed to run command \`${command.command.name}\``, commandRunResult));
|
|
98
98
|
};
|
|
99
|
-
this.#discord.client.on(Events.InteractionCreate,
|
|
99
|
+
this.#discord.client.on(Events.InteractionCreate, (interaction) => void handleCallback(async () => handleInteraction(interaction)));
|
|
100
100
|
console.log("Listening for commands.");
|
|
101
101
|
}
|
|
102
102
|
static async checkRoles({ requiredRoles }, interaction) {
|
|
103
103
|
if (!requiredRoles) return true;
|
|
104
104
|
if (requiredRoles.length > 0) {
|
|
105
|
-
const member = await attempt(() => interaction.guild.members.fetch(interaction.user));
|
|
105
|
+
const member = await attempt(async () => interaction.guild.members.fetch(interaction.user));
|
|
106
106
|
if (isErr(member)) return err(`failed to fetch member '${interaction.user.id}'`, member);
|
|
107
107
|
return member.roles.cache.some((role) => requiredRoles.includes(role.name));
|
|
108
108
|
}
|
|
@@ -118,6 +118,7 @@ var CommandManager = class CommandManager {
|
|
|
118
118
|
if (isErr(reply)) return err(`failed to reply to interaction from command '${interaction.commandName}'`, reply);
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
|
+
//#endregion
|
|
121
122
|
export { CommandManager };
|
|
122
123
|
|
|
123
124
|
//# sourceMappingURL=command-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-manager.js","names":["#commands","#discord","#globalCommandHook"],"sources":["../src/command-manager.ts"],"sourcesContent":["import type {\n ChatInputCommandInteraction,\n Interaction,\n SlashCommandBuilder,\n SlashCommandOptionsOnlyBuilder,\n} from \"discord.js\"\nimport { Collection, Events, MessageFlags, Routes } from \"discord.js\"\nimport type { Result } from \"ts-explicit-errors\"\nimport { attempt, CtxError, err, filterMap, isErr } from \"ts-explicit-errors\"\n\nimport type { DiscordContext } from \"~/bot.ts\"\nimport { components } from \"~/components.ts\"\nimport { handleCallback } from \"~/util.ts\"\n\nexport type CommandRunFn = (interaction: ChatInputCommandInteraction<\"cached\">) => void | Promise<void>\n\nexport interface Command {\n requiredRoles?: string[]\n command: SlashCommandBuilder | SlashCommandOptionsOnlyBuilder\n run: CommandRunFn\n}\n\ninterface CommandHookResult {\n success: boolean\n message?: string\n}\nexport type CommandHook = (\n interaction: ChatInputCommandInteraction<\"cached\">,\n) => CommandHookResult | Promise<CommandHookResult>\n\nexport class CommandManager {\n readonly #commands = new Collection<string, Command>()\n #globalCommandHook?: CommandHook\n readonly #discord: DiscordContext\n\n public constructor(discord: DiscordContext) {\n this.#discord = discord\n }\n\n private getCommandPayload() {\n return this.#commands.map((c) => c.command.toJSON())\n }\n\n private async onReady(fn: () => Result | Promise<Result>) {\n if (this.#discord.client.isReady()) await handleCallback(fn)\n else this.#discord.client.once(Events.ClientReady, async () => await handleCallback(fn))\n }\n\n /*\n * Add a command\n */\n public add(command: Command): void {\n this.#commands.set(command.command.name, command)\n }\n\n public setGlobalCommandHook(commandHook: CommandHook): void {\n this.#globalCommandHook = commandHook\n }\n\n public async register(): Promise<void> {\n const registerResult = await attempt(async () => {\n const route = Routes.applicationCommands(this.#discord.applicationId)\n await this.#discord.rest.put(route, { body: this.getCommandPayload() })\n\n console.log(`Globally registered ${this.#commands.size.toString()} (/) commands.`)\n })\n\n if (isErr(registerResult)) console.error(`failed to register global commands: ${registerResult.messageChain}`)\n }\n\n public async unregister(): Promise<void> {\n const unregisterResult = await attempt(async () => {\n const route = Routes.applicationCommands(this.#discord.applicationId)\n await this.#discord.rest.put(route, { body: [] })\n\n console.log(\"Unregistered global commands.\")\n })\n\n if (isErr(unregisterResult)) console.error(`failed to unregister global commands: ${unregisterResult.messageChain}`)\n }\n\n public async guildRegister() {\n const registerGuildCommands = async (): Promise<Result> => {\n const guilds = await attempt(() => this.#discord.client.guilds.fetch())\n if (isErr(guilds)) return err(\"failed to fetch guilds\", guilds)\n\n const commandPayload = this.getCommandPayload()\n\n const { errors } = await filterMap(guilds.values(), async (guild) => {\n const registerResult = await attempt(async () => {\n const route = Routes.applicationGuildCommands(this.#discord.applicationId, guild.id)\n await this.#discord.rest.put(route, { body: commandPayload })\n console.log(`Registered ${this.#commands.size.toString()} (/) commands in guild '${guild.name}'`)\n })\n\n if (isErr(registerResult))\n return err(`failed to register guild commands in guild '${guild.name}'`, registerResult)\n\n return\n })\n\n if (errors)\n return err(\n `failed to register guild commands in all guilds:\\n${errors.map((error) => error.message).join(\"\\n\")}`,\n undefined,\n )\n }\n\n await this.onReady(async (): Promise<Result> => {\n const registerGuildCommandsResult = await registerGuildCommands()\n if (isErr(registerGuildCommandsResult))\n return err(\"failed to register guild commands\", registerGuildCommandsResult)\n })\n }\n\n public async guildUnregister(): Promise<void> {\n const unregisterGuildCommands = async (): Promise<Result> => {\n const guilds = await attempt(() => this.#discord.client.guilds.fetch())\n if (isErr(guilds)) return err(\"failed to fetch guilds\", guilds)\n\n const { errors } = await filterMap(guilds.values(), async (guild) => {\n const registerResult = await attempt(async () => {\n const route = Routes.applicationGuildCommands(this.#discord.applicationId, guild.id)\n await this.#discord.rest.put(route, { body: [] })\n console.log(`Unregistered commands in guild '${guild.name}'`)\n })\n\n if (isErr(registerResult))\n return err(`failed to unregister guild commands in guild '${guild.name}'`, registerResult)\n\n return\n })\n\n if (errors)\n return err(\n `failed to unregister guild commands in all guilds:\\n${errors.map((error) => error.message).join(\"\\n\")}`,\n undefined,\n )\n }\n\n await this.onReady(async (): Promise<Result> => {\n const unregisterGuildCommandsResult = await unregisterGuildCommands()\n if (isErr(unregisterGuildCommandsResult))\n return err(\"failed to unregister guild commands\", unregisterGuildCommandsResult)\n })\n }\n\n public _listen(): void {\n const handleInteraction = async (interaction: Interaction): Promise<Result> => {\n if (!interaction.isChatInputCommand()) return\n if (!interaction.guildId) return\n\n const guild = await interaction.client.guilds.fetch(interaction.guildId)\n if (isErr(guild))\n return await CommandManager.interactionErrorReply(\n interaction,\n err(`failed to fetch guild with id '${interaction.guildId}'`, guild),\n )\n\n if (!interaction.inCachedGuild())\n return await CommandManager.interactionErrorReply(interaction, \"Guild is not cached. Try again.\")\n\n const command = this.#commands.get(interaction.commandName)\n if (!command)\n return await CommandManager.interactionErrorReply(\n interaction,\n err(`failed to get command with name '${interaction.commandName}'`, undefined),\n )\n\n const hasRequiredRole = await CommandManager.checkRoles(command, interaction)\n if (isErr(hasRequiredRole))\n return await CommandManager.interactionErrorReply(interaction, err(\"failed to check roles\", hasRequiredRole))\n\n if (!hasRequiredRole)\n return await CommandManager.interactionErrorReply(\n interaction,\n \"You do not have one of the required roles to run this command.\",\n \"warn\",\n )\n\n const globalCommandHookResult = await attempt(() =>\n this.#globalCommandHook ? this.#globalCommandHook(interaction) : { success: true },\n )\n if (isErr(globalCommandHookResult))\n return await CommandManager.interactionErrorReply(\n interaction,\n err(\"failed to run global command hook\", globalCommandHookResult),\n )\n\n const {\n success: shouldContinue,\n message: globalCommandHookMessage = \"The global command hook did not succeed.\",\n } = globalCommandHookResult\n if (!shouldContinue)\n return await CommandManager.interactionErrorReply(interaction, globalCommandHookMessage, \"warn\")\n\n const commandRunResult = await attempt(() => command.run(interaction))\n if (isErr(commandRunResult))\n return await CommandManager.interactionErrorReply(\n interaction,\n err(`failed to run command \\`${command.command.name}\\``, commandRunResult),\n )\n }\n\n this.#discord.client.on(\n Events.InteractionCreate,\n async (interaction) => await handleCallback(() => handleInteraction(interaction)),\n )\n\n console.log(\"Listening for commands.\")\n }\n\n private static async checkRoles({ requiredRoles }: Command, interaction: ChatInputCommandInteraction<\"cached\">) {\n if (!requiredRoles) return true\n\n if (requiredRoles.length > 0) {\n const member = await attempt(() => interaction.guild.members.fetch(interaction.user))\n if (isErr(member)) return err(`failed to fetch member '${interaction.user.id}'`, member)\n\n return member.roles.cache.some((role) => requiredRoles.includes(role.name))\n }\n\n return false\n }\n\n private static async interactionErrorReply(\n interaction: ChatInputCommandInteraction,\n error: string | CtxError,\n type: keyof typeof components = \"error\",\n ): Promise<Result> {\n const errorMessage = error instanceof CtxError ? error.messageChain : error\n const errorComponent = components[type](errorMessage)\n\n const reply = await attempt(async () =>\n interaction.deferred\n ? interaction.editReply(errorComponent)\n : interaction.reply({\n components: errorComponent.components,\n flags: [...errorComponent.flags, MessageFlags.Ephemeral],\n }),\n )\n\n if (isErr(reply)) return err(`failed to reply to interaction from command '${interaction.commandName}'`, reply)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-manager.js","names":["#commands","#discord","#globalCommandHook"],"sources":["../src/command-manager.ts"],"sourcesContent":["import type {\n ChatInputCommandInteraction,\n Interaction,\n SlashCommandBuilder,\n SlashCommandOptionsOnlyBuilder,\n} from \"discord.js\"\nimport { Collection, Events, MessageFlags, Routes } from \"discord.js\"\nimport type { Result } from \"ts-explicit-errors\"\nimport { attempt, CtxError, err, filterMap, isErr } from \"ts-explicit-errors\"\n\nimport type { DiscordContext } from \"#/bot.ts\"\nimport { components } from \"#/components.ts\"\nimport { handleCallback } from \"#/util.ts\"\n\nexport type CommandRunFn = (interaction: ChatInputCommandInteraction<\"cached\">) => void | Promise<void>\n\nexport interface Command {\n requiredRoles?: string[]\n command: SlashCommandBuilder | SlashCommandOptionsOnlyBuilder\n run: CommandRunFn\n}\n\ntype CommandHookResult =\n | {\n success: true\n }\n | {\n success: false\n message?: string\n }\n\nexport type CommandHook = (\n interaction: ChatInputCommandInteraction<\"cached\">,\n) => CommandHookResult | Promise<CommandHookResult>\n\nexport class CommandManager {\n readonly #commands = new Collection<string, Command>()\n #globalCommandHook?: CommandHook\n readonly #discord: DiscordContext\n\n public constructor(discord: DiscordContext) {\n this.#discord = discord\n }\n\n private getCommandPayload() {\n return this.#commands.map((c) => c.command.toJSON())\n }\n\n private async onReady(fn: () => Result | Promise<Result>) {\n if (this.#discord.client.isReady()) await handleCallback(fn)\n else this.#discord.client.once(Events.ClientReady, () => void handleCallback(fn))\n }\n\n /*\n * Add a command\n */\n public add(command: Command): void {\n this.#commands.set(command.command.name, command)\n }\n\n public setGlobalCommandHook(commandHook: CommandHook): void {\n this.#globalCommandHook = commandHook\n }\n\n public async register(): Promise<void> {\n const registerResult = await attempt(async () => {\n const route = Routes.applicationCommands(this.#discord.applicationId)\n await this.#discord.rest.put(route, { body: this.getCommandPayload() })\n\n console.log(`Globally registered ${this.#commands.size.toString()} (/) commands.`)\n })\n\n if (isErr(registerResult)) console.error(`failed to register global commands: ${registerResult.messageChain}`)\n }\n\n public async unregister(): Promise<void> {\n const unregisterResult = await attempt(async () => {\n const route = Routes.applicationCommands(this.#discord.applicationId)\n await this.#discord.rest.put(route, { body: [] })\n\n console.log(\"Unregistered global commands.\")\n })\n\n if (isErr(unregisterResult)) console.error(`failed to unregister global commands: ${unregisterResult.messageChain}`)\n }\n\n public async guildRegister() {\n const registerGuildCommands = async (): Promise<Result> => {\n const guilds = await attempt(async () => this.#discord.client.guilds.fetch())\n if (isErr(guilds)) return err(\"failed to fetch guilds\", guilds)\n\n const commandPayload = this.getCommandPayload()\n\n const { errors } = await filterMap(guilds.values(), async (guild) => {\n const registerResult = await attempt(async () => {\n const route = Routes.applicationGuildCommands(this.#discord.applicationId, guild.id)\n await this.#discord.rest.put(route, { body: commandPayload })\n console.log(`Registered ${this.#commands.size.toString()} (/) commands in guild '${guild.name}'`)\n })\n\n if (isErr(registerResult))\n return err(`failed to register guild commands in guild '${guild.name}'`, registerResult)\n\n return\n })\n\n if (errors) {\n return err(\n `failed to register guild commands in all guilds:\\n${errors.map((error) => error.message).join(\"\\n\")}`,\n undefined,\n )\n }\n }\n\n await this.onReady(async (): Promise<Result> => {\n const registerGuildCommandsResult = await registerGuildCommands()\n if (isErr(registerGuildCommandsResult))\n return err(\"failed to register guild commands\", registerGuildCommandsResult)\n })\n }\n\n public async guildUnregister(): Promise<void> {\n const unregisterGuildCommands = async (): Promise<Result> => {\n const guilds = await attempt(async () => this.#discord.client.guilds.fetch())\n if (isErr(guilds)) return err(\"failed to fetch guilds\", guilds)\n\n const { errors } = await filterMap(guilds.values(), async (guild) => {\n const registerResult = await attempt(async () => {\n const route = Routes.applicationGuildCommands(this.#discord.applicationId, guild.id)\n await this.#discord.rest.put(route, { body: [] })\n console.log(`Unregistered commands in guild '${guild.name}'`)\n })\n\n if (isErr(registerResult))\n return err(`failed to unregister guild commands in guild '${guild.name}'`, registerResult)\n\n return\n })\n\n if (errors) {\n return err(\n `failed to unregister guild commands in all guilds:\\n${errors.map((error) => error.message).join(\"\\n\")}`,\n undefined,\n )\n }\n }\n\n await this.onReady(async (): Promise<Result> => {\n const unregisterGuildCommandsResult = await unregisterGuildCommands()\n if (isErr(unregisterGuildCommandsResult))\n return err(\"failed to unregister guild commands\", unregisterGuildCommandsResult)\n })\n }\n\n public _listen(): void {\n const handleInteraction = async (interaction: Interaction): Promise<Result> => {\n if (!interaction.isChatInputCommand()) return\n if (!interaction.guildId) return\n\n const guild = await interaction.client.guilds.fetch(interaction.guildId)\n if (isErr(guild)) {\n return CommandManager.interactionErrorReply(\n interaction,\n err(`failed to fetch guild with id '${interaction.guildId}'`, guild),\n )\n }\n\n if (!interaction.inCachedGuild())\n return CommandManager.interactionErrorReply(interaction, \"Guild is not cached. Try again.\")\n\n const command = this.#commands.get(interaction.commandName)\n if (!command) {\n return CommandManager.interactionErrorReply(\n interaction,\n err(`failed to get command with name '${interaction.commandName}'`, undefined),\n )\n }\n\n const hasRequiredRole = await CommandManager.checkRoles(command, interaction)\n if (isErr(hasRequiredRole))\n return CommandManager.interactionErrorReply(interaction, err(\"failed to check roles\", hasRequiredRole))\n\n if (!hasRequiredRole) {\n return CommandManager.interactionErrorReply(\n interaction,\n \"You do not have one of the required roles to run this command.\",\n \"warn\",\n )\n }\n\n const globalCommandHookResult = await attempt(async () =>\n this.#globalCommandHook ? this.#globalCommandHook(interaction) : ({ success: true } as const),\n )\n if (isErr(globalCommandHookResult)) {\n return CommandManager.interactionErrorReply(\n interaction,\n err(\"failed to run global command hook\", globalCommandHookResult),\n )\n }\n\n if (!globalCommandHookResult.success) {\n return CommandManager.interactionErrorReply(\n interaction,\n globalCommandHookResult.message ?? \"The global command hook did not succeed.\",\n \"warn\",\n )\n }\n\n const commandRunResult = await attempt(async () => command.run(interaction))\n if (isErr(commandRunResult)) {\n return CommandManager.interactionErrorReply(\n interaction,\n err(`failed to run command \\`${command.command.name}\\``, commandRunResult),\n )\n }\n }\n\n this.#discord.client.on(\n Events.InteractionCreate,\n (interaction) => void handleCallback(async () => handleInteraction(interaction)),\n )\n\n console.log(\"Listening for commands.\")\n }\n\n private static async checkRoles({ requiredRoles }: Command, interaction: ChatInputCommandInteraction<\"cached\">) {\n if (!requiredRoles) return true\n\n if (requiredRoles.length > 0) {\n const member = await attempt(async () => interaction.guild.members.fetch(interaction.user))\n if (isErr(member)) return err(`failed to fetch member '${interaction.user.id}'`, member)\n\n return member.roles.cache.some((role) => requiredRoles.includes(role.name))\n }\n\n return false\n }\n\n private static async interactionErrorReply(\n interaction: ChatInputCommandInteraction,\n error: string | CtxError,\n type: keyof typeof components = \"error\",\n ): Promise<Result> {\n const errorMessage = error instanceof CtxError ? error.messageChain : error\n const errorComponent = components[type](errorMessage)\n\n const reply = await attempt(async () =>\n interaction.deferred\n ? interaction.editReply(errorComponent)\n : interaction.reply({\n components: errorComponent.components,\n flags: [...errorComponent.flags, MessageFlags.Ephemeral],\n }),\n )\n\n if (isErr(reply)) return err(`failed to reply to interaction from command '${interaction.commandName}'`, reply)\n }\n}\n"],"mappings":"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"}
|
package/dist/components.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.d.ts","names":[],"sources":["../src/components.ts"],"
|
|
1
|
+
{"version":3,"file":"components.d.ts","names":[],"sources":["../src/components.ts"],"mappings":";;;cA0Ba,UAAA;EAAA"}
|
package/dist/components.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ContainerBuilder, MessageFlags, SeparatorSpacingSize } from "discord.js";
|
|
2
|
+
//#region src/components.ts
|
|
2
3
|
const error = (message) => ({
|
|
3
4
|
components: [new ContainerBuilder().setAccentColor(16711680).addTextDisplayComponents((t) => t.setContent("**Error**")).addSeparatorComponents((s) => s.setSpacing(SeparatorSpacingSize.Small)).addTextDisplayComponents((t) => t.setContent(message))],
|
|
4
5
|
flags: [MessageFlags.IsComponentsV2]
|
|
@@ -11,6 +12,7 @@ const components = {
|
|
|
11
12
|
error,
|
|
12
13
|
warn
|
|
13
14
|
};
|
|
15
|
+
//#endregion
|
|
14
16
|
export { components };
|
|
15
17
|
|
|
16
18
|
//# sourceMappingURL=components.js.map
|
package/dist/components.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.js","names":[],"sources":["../src/components.ts"],"sourcesContent":["import { ContainerBuilder, MessageFlags, SeparatorSpacingSize } from \"discord.js\"\n\nconst error = (message: string) =>\n ({\n components: [\n new ContainerBuilder()\n .setAccentColor(0xff_00_00)\n .addTextDisplayComponents((t) => t.setContent(\"**Error**\"))\n .addSeparatorComponents((s) => s.setSpacing(SeparatorSpacingSize.Small))\n .addTextDisplayComponents((t) => t.setContent(message)),\n ],\n flags: [MessageFlags.IsComponentsV2],\n }) as const\n\nconst warn = (message: string) =>\n ({\n components: [\n new ContainerBuilder()\n .setAccentColor(0xff_bf_00)\n .addTextDisplayComponents((t) => t.setContent(\"**Warning**\"))\n .addSeparatorComponents((s) => s.setSpacing(SeparatorSpacingSize.Small))\n .addTextDisplayComponents((t) => t.setContent(message)),\n ],\n flags: [MessageFlags.IsComponentsV2],\n }) as const\n\nexport const components = {\n error,\n warn,\n} as const\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components.js","names":[],"sources":["../src/components.ts"],"sourcesContent":["import { ContainerBuilder, MessageFlags, SeparatorSpacingSize } from \"discord.js\"\n\nconst error = (message: string) =>\n ({\n components: [\n new ContainerBuilder()\n .setAccentColor(0xff_00_00)\n .addTextDisplayComponents((t) => t.setContent(\"**Error**\"))\n .addSeparatorComponents((s) => s.setSpacing(SeparatorSpacingSize.Small))\n .addTextDisplayComponents((t) => t.setContent(message)),\n ],\n flags: [MessageFlags.IsComponentsV2],\n }) as const\n\nconst warn = (message: string) =>\n ({\n components: [\n new ContainerBuilder()\n .setAccentColor(0xff_bf_00)\n .addTextDisplayComponents((t) => t.setContent(\"**Warning**\"))\n .addSeparatorComponents((s) => s.setSpacing(SeparatorSpacingSize.Small))\n .addTextDisplayComponents((t) => t.setContent(message)),\n ],\n flags: [MessageFlags.IsComponentsV2],\n }) as const\n\nexport const components = {\n error,\n warn,\n} as const\n"],"mappings":";;AAEA,MAAM,SAAS,aACZ;CACC,YAAY,CACV,IAAI,iBAAiB,CAAC,CACnB,eAAe,QAAU,CAAC,CAC1B,0BAA0B,MAAM,EAAE,WAAW,WAAW,CAAC,CAAC,CAC1D,wBAAwB,MAAM,EAAE,WAAW,qBAAqB,KAAK,CAAC,CAAC,CACvE,0BAA0B,MAAM,EAAE,WAAW,OAAO,CAAC,CAC1D;CACA,OAAO,CAAC,aAAa,cAAc;AACrC;AAEF,MAAM,QAAQ,aACX;CACC,YAAY,CACV,IAAI,iBAAiB,CAAC,CACnB,eAAe,QAAU,CAAC,CAC1B,0BAA0B,MAAM,EAAE,WAAW,aAAa,CAAC,CAAC,CAC5D,wBAAwB,MAAM,EAAE,WAAW,qBAAqB,KAAK,CAAC,CAAC,CACvE,0BAA0B,MAAM,EAAE,WAAW,OAAO,CAAC,CAC1D;CACA,OAAO,CAAC,aAAa,cAAc;AACrC;AAEF,MAAa,aAAa;CACxB;CACA;AACF"}
|
package/dist/event-manager.d.ts
CHANGED
|
@@ -3,11 +3,11 @@ import { Client, ClientEvents } from "discord.js";
|
|
|
3
3
|
|
|
4
4
|
//#region src/event-manager.d.ts
|
|
5
5
|
type ValidEvents = keyof ClientEvents;
|
|
6
|
-
type EventHandler<E
|
|
6
|
+
type EventHandler<E extends ValidEvents = ValidEvents> = (client: Client, ...args: ClientEvents[E]) => void | Promise<void>;
|
|
7
7
|
type EventHandlerMap = { [E in ValidEvents]: EventHandler<E> };
|
|
8
|
-
interface SingleEvent<E
|
|
9
|
-
event: E
|
|
10
|
-
handler: EventHandlerMap[E
|
|
8
|
+
interface SingleEvent<E extends ValidEvents = ValidEvents> {
|
|
9
|
+
event: E;
|
|
10
|
+
handler: EventHandlerMap[E];
|
|
11
11
|
}
|
|
12
12
|
declare class EventManager {
|
|
13
13
|
#private;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-manager.d.ts","names":[],"sources":["../src/event-manager.ts"],"
|
|
1
|
+
{"version":3,"file":"event-manager.d.ts","names":[],"sources":["../src/event-manager.ts"],"mappings":";;;;KAOK,WAAA,SAAoB,YAAY;AAAA,KAEhC,YAAA,WAAuB,WAAA,GAAc,WAAA,KACxC,MAAA,EAAQ,MAAA,KACL,IAAA,EAAM,YAAA,CAAa,CAAA,aACZ,OAAA;AAAA,KAEP,eAAA,WACG,WAAA,GAAc,YAAA,CAAa,CAAA;AAAA,UAGzB,WAAA,WAAsB,WAAA,GAAc,WAAA;EAC5C,KAAA,EAAO,CAAA;EACP,OAAA,EAAS,eAAA,CAAgB,CAAA;AAAA;AAAA,cAGd,YAAA;EAAA;cAIQ,OAAA,EAAS,cAAA;EAOrB,GAAA,WAAc,WAAA,EAAa,KAAA,EAAO,WAAA,CAAY,CAAA;EAI9C,OAAA;AAAA;AAAA,KAiBG,KAAA,WACJ,WAAA,GAAc,WAAA,CAAY,CAAA,IAChC,WAAA"}
|
package/dist/event-manager.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { handleCallback } from "./util.js";
|
|
2
2
|
import { attempt, err, isErr } from "ts-explicit-errors";
|
|
3
|
+
//#region src/event-manager.ts
|
|
3
4
|
var EventManager = class {
|
|
4
5
|
#events = [];
|
|
5
6
|
#discord;
|
|
@@ -10,16 +11,18 @@ var EventManager = class {
|
|
|
10
11
|
this.#events.push(event);
|
|
11
12
|
}
|
|
12
13
|
_listen() {
|
|
13
|
-
this.#events
|
|
14
|
-
const handleEvent = async (...args) => {
|
|
15
|
-
const eventHandlerResult = await attempt(() => singleEvent.handler(this.#discord.client, ...args));
|
|
16
|
-
if (isErr(eventHandlerResult)) return err(`failed to handle event '${singleEvent.event}'`, eventHandlerResult);
|
|
17
|
-
};
|
|
18
|
-
this.#discord.client.on(singleEvent.event, async (...args) => await handleCallback(() => handleEvent(...args)));
|
|
19
|
-
});
|
|
14
|
+
for (const singleEvent of this.#events) this.#listen(singleEvent);
|
|
20
15
|
console.log(`Listening for (${this.#events.length.toString()}) events.`);
|
|
21
16
|
}
|
|
17
|
+
#listen(singleEvent) {
|
|
18
|
+
const handleEvent = async (...args) => {
|
|
19
|
+
const eventHandlerResult = await attempt(async () => singleEvent.handler(this.#discord.client, ...args));
|
|
20
|
+
if (isErr(eventHandlerResult)) return err(`failed to handle event '${singleEvent.event}'`, eventHandlerResult);
|
|
21
|
+
};
|
|
22
|
+
this.#discord.client.on(singleEvent.event, (...args) => void handleCallback(async () => handleEvent(...args)));
|
|
23
|
+
}
|
|
22
24
|
};
|
|
25
|
+
//#endregion
|
|
23
26
|
export { EventManager };
|
|
24
27
|
|
|
25
28
|
//# sourceMappingURL=event-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-manager.js","names":["#events","#discord"],"sources":["../src/event-manager.ts"],"sourcesContent":["import type { Client, ClientEvents } from \"discord.js\"\nimport type { Result } from \"ts-explicit-errors\"\nimport { attempt, err, isErr } from \"ts-explicit-errors\"\n\nimport type { DiscordContext } from \"
|
|
1
|
+
{"version":3,"file":"event-manager.js","names":["#events","#discord","#listen"],"sources":["../src/event-manager.ts"],"sourcesContent":["import type { Client, ClientEvents } from \"discord.js\"\nimport type { Result } from \"ts-explicit-errors\"\nimport { attempt, err, isErr } from \"ts-explicit-errors\"\n\nimport type { DiscordContext } from \"#/bot.ts\"\nimport { handleCallback } from \"#/util.ts\"\n\ntype ValidEvents = keyof ClientEvents\n\ntype EventHandler<E extends ValidEvents = ValidEvents> = (\n client: Client,\n ...args: ClientEvents[E]\n) => void | Promise<void>\n\ntype EventHandlerMap = {\n [E in ValidEvents]: EventHandler<E>\n}\n\ninterface SingleEvent<E extends ValidEvents = ValidEvents> {\n event: E\n handler: EventHandlerMap[E]\n}\n\nexport class EventManager {\n readonly #events: SingleEvent[] = []\n readonly #discord: DiscordContext\n\n public constructor(discord: DiscordContext) {\n this.#discord = discord\n }\n\n /*\n * Add an event listener\n */\n public add<N extends ValidEvents>(event: SingleEvent<N>): void {\n this.#events.push(event)\n }\n\n public _listen(): void {\n for (const singleEvent of this.#events) this.#listen(singleEvent)\n\n console.log(`Listening for (${this.#events.length.toString()}) events.`)\n }\n\n // generic over E so `event` and `handler` stay correlated, see microsoft/TypeScript#47109\n #listen<E extends ValidEvents>(singleEvent: SingleEvent<E>): void {\n const handleEvent = async (...args: ClientEvents[E]): Promise<Result> => {\n const eventHandlerResult = await attempt(async () => singleEvent.handler(this.#discord.client, ...args))\n if (isErr(eventHandlerResult)) return err(`failed to handle event '${singleEvent.event}'`, eventHandlerResult)\n }\n\n this.#discord.client.on(singleEvent.event, (...args) => void handleCallback(async () => handleEvent(...args)))\n }\n}\n\nexport type Event = {\n [E in ValidEvents]: SingleEvent<E>\n}[ValidEvents]\n"],"mappings":";;;AAuBA,IAAa,eAAb,MAA0B;CACxB,UAAkC,CAAC;CACnC;CAEA,YAAmB,SAAyB;EAC1C,KAAKC,WAAW;CAClB;CAKA,IAAkC,OAA6B;EAC7D,KAAKD,QAAQ,KAAK,KAAK;CACzB;CAEA,UAAuB;EACrB,KAAK,MAAM,eAAe,KAAKA,SAAS,KAAKE,QAAQ,WAAW;EAEhE,QAAQ,IAAI,kBAAkB,KAAKF,QAAQ,OAAO,SAAS,EAAE,UAAU;CACzE;CAGA,QAA+B,aAAmC;EAChE,MAAM,cAAc,OAAO,GAAG,SAA2C;GACvE,MAAM,qBAAqB,MAAM,QAAQ,YAAY,YAAY,QAAQ,KAAKC,SAAS,QAAQ,GAAG,IAAI,CAAC;GACvG,IAAI,MAAM,kBAAkB,GAAG,OAAO,IAAI,2BAA2B,YAAY,MAAM,IAAI,kBAAkB;EAC/G;EAEA,KAAKA,SAAS,OAAO,GAAG,YAAY,QAAQ,GAAG,SAAS,KAAK,eAAe,YAAY,YAAY,GAAG,IAAI,CAAC,CAAC;CAC/G;AACF"}
|
package/dist/util.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { isErr } from "ts-explicit-errors";
|
|
2
|
-
|
|
2
|
+
//#region src/util.ts
|
|
3
|
+
const handleCallback = async (fn) => {
|
|
3
4
|
const result = await fn();
|
|
4
5
|
if (isErr(result)) console.error(result.messageChain);
|
|
5
|
-
}
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
6
8
|
export { handleCallback };
|
|
7
9
|
|
|
8
10
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","names":[],"sources":["../src/util.ts"],"sourcesContent":["import type { Result } from \"ts-explicit-errors\"\nimport { isErr } from \"ts-explicit-errors\"\n\nexport async
|
|
1
|
+
{"version":3,"file":"util.js","names":[],"sources":["../src/util.ts"],"sourcesContent":["import type { Result } from \"ts-explicit-errors\"\nimport { isErr } from \"ts-explicit-errors\"\n\nexport const handleCallback = async (fn: () => Result | Promise<Result>) => {\n const result = await fn()\n if (isErr(result)) console.error(result.messageChain)\n}\n"],"mappings":";;AAGA,MAAa,iBAAiB,OAAO,OAAuC;CAC1E,MAAM,SAAS,MAAM,GAAG;CACxB,IAAI,MAAM,MAAM,GAAG,QAAQ,MAAM,OAAO,YAAY;AACtD"}
|
package/package.json
CHANGED
|
@@ -1,51 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discord-bot-shared",
|
|
3
|
-
"version": "0.16.
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "0.16.2",
|
|
5
4
|
"description": "Modules for creating discord bots.",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/adamhl8/discord-bot-shared.git"
|
|
9
|
-
},
|
|
10
5
|
"homepage": "https://github.com/adamhl8/discord-bot-shared",
|
|
11
6
|
"bugs": {
|
|
12
7
|
"url": "https://github.com/adamhl8/discord-bot-shared/issues"
|
|
13
8
|
},
|
|
9
|
+
"license": "MIT",
|
|
14
10
|
"author": {
|
|
15
|
-
"email": "adamhl@pm.me",
|
|
16
11
|
"name": "Adam Langbert",
|
|
12
|
+
"email": "adamhl@pm.me",
|
|
17
13
|
"url": "https://github.com/adamhl8"
|
|
18
14
|
},
|
|
19
|
-
"
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/adamhl8/discord-bot-shared.git"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"imports": {
|
|
24
|
+
"#/*": "./src/*"
|
|
25
|
+
},
|
|
20
26
|
"exports": {
|
|
21
27
|
".": {
|
|
22
28
|
"types": "./dist/index.d.ts",
|
|
23
29
|
"import": "./dist/index.js"
|
|
24
30
|
}
|
|
25
31
|
},
|
|
26
|
-
"files": ["dist/"],
|
|
27
32
|
"scripts": {
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
33
|
+
"lint": "markdown-toc -i --bullets '-' --maxdepth 3 ./README.md && oxfmt && oxlint --fix --fix-suggestions --fix-dangerously && adamhl8-knip",
|
|
34
|
+
"bump-deps": "nub update -L && rm -f lock.yaml && nub i && oxfmt lock.yaml",
|
|
35
|
+
"bundle": "nub run lint && tsdown",
|
|
36
|
+
"release": "gh workflow run release.yml",
|
|
37
|
+
"release:run": "release-it --ci -i \"$(adamhl8-cliff --bumped-version)\"",
|
|
38
|
+
"prepare": "lefthook install"
|
|
32
39
|
},
|
|
33
|
-
"
|
|
34
|
-
"
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"ts-explicit-errors": "^4.1.2"
|
|
35
42
|
},
|
|
36
43
|
"devDependencies": {
|
|
37
|
-
"@adamhl8/configs": "^0.
|
|
38
|
-
"@arethetypeswrong/core": "^0.18.
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"
|
|
42
|
-
"
|
|
44
|
+
"@adamhl8/configs": "^0.24.10",
|
|
45
|
+
"@arethetypeswrong/core": "^0.18.4",
|
|
46
|
+
"@commitlint/cli": "^21.2.0",
|
|
47
|
+
"@commitlint/config-conventional": "^21.2.0",
|
|
48
|
+
"@types/node": "^26.1.0",
|
|
49
|
+
"discord.js": "^14.26.4",
|
|
50
|
+
"knip": "^6.23.0",
|
|
43
51
|
"markdown-toc": "^1.2.0",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
52
|
+
"oxfmt": "^0.57.0",
|
|
53
|
+
"oxlint": "^1.72.0",
|
|
54
|
+
"oxlint-tsgolint": "^0.24.0",
|
|
55
|
+
"publint": "^0.3.21",
|
|
56
|
+
"release-it": "^20.2.1",
|
|
57
|
+
"tsdown": "^0.22.3",
|
|
58
|
+
"typescript": "^6.0.3"
|
|
47
59
|
},
|
|
48
|
-
"
|
|
49
|
-
"
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"discord.js": "^14.0.0"
|
|
50
62
|
}
|
|
51
63
|
}
|