discord-bot-shared 0.13.0 → 0.14.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 adamhl8
3
+ Copyright (c) 2025 adamhl8
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,171 +1,288 @@
1
1
  # discord-bot-shared
2
2
 
3
- **This readme is currently out of date.**
3
+ A small package that makes creating [discord.js](https://github.com/discordjs/discord.js) bots a bit easier. It allows you easily create and register bot commands/events, handle runtime errors, and more.
4
4
 
5
- A module that makes creating discord.js bots a bit easier.
6
-
7
- ## Installation/Usage
5
+ ---
8
6
 
9
- ```
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Creating a `Bot` instance](#creating-a-bot-instance)
10
+ - [Commands](#commands)
11
+ - [Creating a slash command](#creating-a-slash-command)
12
+ - [Adding and registering commands](#adding-and-registering-commands)
13
+ - [Unregistering commands](#unregistering-commands)
14
+ - [Global Command Hook](#global-command-hook)
15
+ - [Events](#events)
16
+ - [Listening for events](#listening-for-events)
17
+ - [Adding and registering events](#adding-and-registering-events)
18
+ - [Error Handling](#error-handling)
19
+ - [Commands](#commands-1)
20
+ - [Events](#events-1)
21
+ - [Utilities](#utilities)
22
+ - [getChannel](#getchannel)
23
+
24
+ ## Installation
25
+
26
+ ```sh
10
27
  npm install discord-bot-shared
11
28
  ```
12
29
 
13
- - This module expects a `BOT_TOKEN` and `CLIENT_ID` environment variable to login.
14
- - By default, commands are registered globally. To register commands to a specific guild, you can optionally provide `GUILD_ID`.
30
+ ## Quick Start
15
31
 
16
- ```
17
- // index.ts
18
- import login from 'discord-bot-shared'
19
- import { ClientOptions, GatewayIntentBits as Intents, Partials } from 'discord.js'
32
+ Let's create a simple bot with one slash command.
20
33
 
21
- const botIntents: ClientOptions = {
22
- intents: [Intents.Guilds],
23
- partials: [Partials.Reaction],
24
- }
34
+ In **`ping.ts`:**
25
35
 
26
- const bot = await login(botIntents, import.meta.url)
36
+ ```ts
37
+ import { Command } from "discord-bot-shared"
38
+ import { SlashCommandBuilder } from "discord.js"
27
39
 
28
- export default bot
40
+ const ping: Command = {
41
+ command: new SlashCommandBuilder().setName("ping").setDescription("I'll respond with pong!").toJSON(),
42
+ async run(interaction) {
43
+ await interaction.reply("Pong!")
44
+ },
45
+ }
46
+
47
+ export default ping
29
48
  ```
30
49
 
31
- **You must have a directory names `events` and `commands` next to your `index.ts` (or wherever you are importing `login()` from).**
50
+ In **`index.ts`:**
32
51
 
33
- ```
34
- .
35
- └── src/
36
- ├── events/
37
- │ └── someEvent.ts
38
- ├── commands/
39
- │ └── someCommand.ts
40
- └── index.ts
52
+ ```ts
53
+ import Bot from "discord-bot-shared"
54
+ import { ClientOptions, GatewayIntentBits } from "discord.js"
55
+
56
+ import ping from "./ping"
57
+
58
+ // Get applicationId and token from environment variables
59
+ const applicationId = process.env.APPLICATION_ID ?? ""
60
+ const token = process.env.BOT_TOKEN ?? ""
61
+
62
+ const clientOptions: ClientOptions = {
63
+ intents: [GatewayIntentBits.Guilds],
64
+ }
65
+
66
+ const bot = new Bot({ applicationId, token, clientOptions })
67
+
68
+ bot.commands.add(ping)
69
+
70
+ await bot.commands.register()
71
+ await bot.login()
41
72
  ```
42
73
 
43
- ### Events
74
+ That's it! You now have bot that will respond to the slash command `/ping` with "Pong!".
44
75
 
45
- This module registers your bot's events by `import`ing each file under your `events` directory. Events are registered as a side-effect of the import.
76
+ ## Creating a `Bot` instance
46
77
 
78
+ The `Bot` constructor takes an object that contains your bot's `applicationId`, secret `token`, and Discord `clientOptions`. See this [discord.js guide page](https://discordjs.guide/popular-topics/intents.html) for more info on setting up bot intents.
79
+
80
+ ```ts
81
+ const bot = new Bot({ applicationId, token, clientOptions })
47
82
  ```
48
- // guildMemberAdd.ts
49
- import bot from '../index.js'
50
83
 
51
- bot.on('guildMemberAdd', (member) => {
52
- // do stuff
53
- })
84
+ Once you have your bot setup and are ready for it to start listening for the commands and events you've added:
85
+
86
+ ```ts
87
+ await bot.login()
54
88
  ```
55
89
 
56
- ### Commands
90
+ ## Commands
57
91
 
58
- Your commands are registered by `import`ing the default export of each command file.
92
+ ### Creating a slash command
59
93
 
60
- ```
61
- // myCommand.ts
62
- import { Command } from 'discord-bot-shared'
63
- import { SlashCommandBuilder } from 'discord.js'
94
+ Commands can be created by constructing `Command` objects that will be added to the bot later.
95
+
96
+ ```ts
97
+ import { Command } from "discord-bot-shared"
98
+ import { SlashCommandBuilder } from "discord.js"
64
99
 
65
- const myCommand: Command = {
66
- command: new SlashCommandBuilder()
67
- .setName('my-command')
68
- .setDescription('This command does stuff.') as SlashCommandBuilder,
69
- run: (interaction) => {
70
- // do stuff
100
+ const ping: Command = {
101
+ command: new SlashCommandBuilder().setName("ping").setDescription("I'll respond with pong!").toJSON(),
102
+ async run(interaction) {
103
+ await interaction.reply("Pong!")
71
104
  },
72
105
  }
73
106
 
74
- export default myCommand
107
+ export default ping
75
108
  ```
76
109
 
77
- Your `run` function is passed the command interaction that initiated the command.
110
+ Make sure to call `.toJSON()` on `SlashCommandBuilder`.
78
111
 
79
- ### Exports
112
+ You can optionally provide a `requiredRoles` string array. If the member initiating the command has _any_ of the roles provided in this array, they will be allowed to run the command.
80
113
 
81
- The following functions and interfaces/types are exported by this module:
114
+ ```ts
115
+ const ping: Command = {
116
+ requiredRoles: ["cool guy", "cooler guy"], // Only members that have a role with the name "cool guy" OR "cooler guy" can run this command.
117
+ command: // ...
118
+ run: // ...
119
+ }
120
+ ```
82
121
 
83
- ---
122
+ ### Adding and registering commands
84
123
 
85
- #### `function login`
124
+ You can add commands to the bot like so:
86
125
 
87
- ```
88
- async function login(
89
- botIntents: ClientOptions,
90
- projectMetaURL: string,
91
- interactionCheck?: InteractionCheck,
92
- ): Promise<Client>
126
+ ```ts
127
+ bot.commands.add(ping)
93
128
  ```
94
129
 
95
- - `botIntents` is a discord.js `ClientOptions` object.
96
- - `projectMetaURL` should always be passed `import.meta.url`. This is used to find and register your events and commands.
97
- - Optionally provide an `interactionCheck` function that returns a boolean. This function is called right before trying to run a command. The command will only run if `interactionCheck` returns true.
98
- - The `InteractionCheck` type is also exported by this module.
130
+ Commands must be registered before they will appear in Discord.
99
131
 
100
- ---
132
+ ```ts
133
+ await bot.commands.register()
134
+ ```
101
135
 
102
- #### `function getGuildCache`
136
+ This registers commands globally (for all servers). It's not really recommended to register commands every time your bot starts up as you may get rate-limited by Discord.
103
137
 
104
- Returns an object that contains the guild and the following freshly fetched guild collections: `channels, emojis, members, roles`.
138
+ ### Unregistering commands
105
139
 
140
+ ```ts
141
+ await bot.commands.unregisterApplicationCommands()
106
142
  ```
107
- async function getGuildCache()
143
+
144
+ This will unregister all commands globally.
145
+
146
+ ### Global Command Hook
147
+
148
+ You can optionally add a global command hook to your bot. This is a function that will be called before your command's `run` function.
149
+
150
+ - The global command hook function must return a `boolean`.
151
+ - If `true` is returned, the initiated command will run.
152
+
153
+ ```ts
154
+ bot.commands.setGlobalCommandHook(commandHook)
108
155
  ```
109
156
 
110
- - For example, a common pattern I use is something like this:
157
+ This allows you to perform certain actions or make checks before _any_ command runs. For example, you could do something like this:
111
158
 
159
+ ```ts
160
+ function commandHook(interaction: ChatInputCommandInteraction<"cached">) {
161
+ if (interaction.channelId === "123456789") {
162
+ return true
163
+ } else {
164
+ throwUserError("This command was not initiated in the right channel.")
165
+ }
166
+ }
167
+
168
+ bot.commands.setGlobalCommandHook(commandHook)
112
169
  ```
113
- const { members } = await getGuildCache()
114
- // do stuff with members
170
+
171
+ It's intended that you throw an error in the case you don't want the command to run rather than returning `false`. Otherwise, a generic error message will be displayed: `The global command hook returned false.`
172
+
173
+ `throwUserError` is a special helper function. See [Error Handling](#error-handling) for more info.
174
+
175
+ ## Events
176
+
177
+ ### Listening for events
178
+
179
+ You can create an `Event` object that will be added to the bot later.
180
+
181
+ ```ts
182
+ import { Event } from "discord-bot-shared"
183
+ import { Events } from "discord.js"
184
+
185
+ const logNewMember: Event = {
186
+ event: Events.GuildMemberAdd,
187
+ handler(client, member) {
188
+ console.log(`${member.user.username} joined the server.`)
189
+ },
190
+ }
191
+
192
+ export default logNewMember
115
193
  ```
116
194
 
117
- ---
195
+ The `Client` instance is always passed as the first argument to the `handler`. The rest of the arguments will be correctly typed based on the event you specify. Also, the `handler` can be `async` if needed.
118
196
 
119
- #### `interface Command`
197
+ ### Adding and registering events
120
198
 
121
- This interface defines the structure of your bot's commands. See above for an example of a command.
199
+ You can add events to the bot like so:
122
200
 
201
+ ```ts
202
+ bot.events.add(logNewMember)
123
203
  ```
124
- interface Command {
125
- requiredRoles?: string[]
126
- command: SlashCommandBuilder
127
- run: (interaction: ChatInputCommandInteraction) => void | Promise<void>
204
+
205
+ Unlike commands, events do not need to be registered separately. They will be listened for once the bot is logged in.
206
+
207
+ ## Error Handling
208
+
209
+ This package makes it much easier to handle errors that are thrown during a command or event.
210
+
211
+ There are two helper functions you can import for throwing errors: `throwError` and `throwUserError`. (These also conveniently allow you to throw an error as an expression.)
212
+
213
+ - `throwError(message: string)`: Throw a `new Error` with `message`.
214
+ - `throwUserError(message: string)`: Throw a `new UserError` with `message`.
215
+
216
+ The usage of these is explained below.
217
+
218
+ ### Commands
219
+
220
+ **TLDR:** Use `throwError` to display an error **with the stack trace** in the interaction reply. Use `throwUserError` to display the error message **only** in the interaction reply. That means by default, any instance of `Error` thrown (say by some function you don't own), will be displayed in the interaction reply with its stack trace (which is probably what you want).
221
+
222
+ When an error is thrown during a command, the interaction is replied to with the error message. For example:
223
+
224
+ ```ts
225
+ import { Command, throwError } from "discord-bot-shared"
226
+ import { SlashCommandBuilder } from "discord.js"
227
+
228
+ const ping: Command = {
229
+ command: new SlashCommandBuilder().setName("ping").setDescription("I'll respond with pong!").toJSON(),
230
+ async run(interaction) {
231
+ if (interaction.member.id === "12345") {
232
+ await interaction.reply("Pong!")
233
+ } else {
234
+ throwError("Expected member with ID: 12345")
235
+ }
236
+ },
128
237
  }
129
238
  ```
130
239
 
131
- - Optionally provide `requiredRoles` string array. If the member initiating the command has _any_ of the roles provided in this array, they will be allowed to run the command.
132
- - **You may have to type cast your command `as SlashCommandBuilder` due to the way discord.js' `SlashCommandBuilder` works.**
133
- - `run` is the final function that will be called to run your command.
240
+ If a member with an ID of `12345` does not initiate this command, the bot will respond with `There was an error while running this command.` along with the error **and stack trace**.
134
241
 
135
- ---
242
+ In most cases, you probably want to display a clean (i.e. without the stack trace) error message. That's where `throwUserError` comes in. If this type of error is thrown, only the provided error message is displayed.
136
243
 
137
- #### `function getChannel`
244
+ As a more complete example, let's say we have some command that allows a member to level up when they have enough XP:
138
245
 
139
- Returns the guild channel of the given name/ID and type, otherwise returns `undefined`.
246
+ ```ts
247
+ import { Command, throwUserError } from "discord-bot-shared"
248
+ import { SlashCommandBuilder } from "discord.js"
140
249
 
141
- ```
142
- async function getChannel<T extends NonThreadGuildBasedChannel>(
143
- channelNameOrId: string,
144
- channelType: NonThreadGuildBasedChannelType,
145
- ): Promise<T | undefined>
250
+ const levelUp: Command = {
251
+ command: new SlashCommandBuilder().setName("level-up").setDescription("Level up if you have enough XP.").toJSON(),
252
+ async run(interaction) {
253
+ const memberXP = getMemberXP(interaction.member.id) // This might throw!
254
+
255
+ if (memberXP >= 100) {
256
+ levelUpMember(interaction.member.id)
257
+ await interaction.reply("Level up!")
258
+ } else {
259
+ throwUserError("You don't have enough XP to level up!")
260
+ }
261
+ },
262
+ }
146
263
  ```
147
264
 
148
- - `T` can be one of `TextChannel | VoiceChannel | NewsChannel | StageChannel | CategoryChannel`.
149
- - `channelType` is a discord.js `ChannelType`. Can be one of `GuildText | GuildVoice | GuildNews | GuildStageVoice | GuildCategory` (prepended with `ChannelType`).
150
- - It is intended that you pass in a type for `T` that matches `channelType`. The returned channel is cast as whatever type is passed in.
151
- - For example:
265
+ - Say `getMemberXP` throws because the underlying database call fails. The member that initiated the command will get a response with the error message and stack trace (which they can then send to you so you can debug the error).
266
+ - If the member doesn't have enough XP, they will receive the message about not having enough XP (no stack trace).
152
267
 
153
- ```
154
- const someTextChannel = await getChannel<TextChannel>('some-text-channel', ChannelType.GuildText)
155
- ```
268
+ **This means that you should generally _not_ try to catch/handle errors in your commands and let it be handled by the bot.**
156
269
 
157
- ---
270
+ ### Events
158
271
 
159
- #### Channel Type Guards
272
+ For events, all errors are caught and logged with `console.error`.
160
273
 
161
- These are channel type guards that you may need to use.
274
+ ## Utilities
162
275
 
163
- ```
164
- function isTextChannel(channel: BaseChannel | APIPartialChannel): channel is TextChannel
165
- ```
276
+ ### getChannel
166
277
 
167
- ```
168
- function isCategoryChannel(channel: BaseChannel): channel is CategoryChannel
278
+ Returns the guild channel of the given name/ID and type, otherwise throws.
279
+
280
+ ```ts
281
+ import { getChannel } from "discord-bot-shared"
282
+ import { ChannelType } from "discord.js"
283
+
284
+ // guild is of type Guild from discord.js
285
+ const someTextChannel = await getChannel(guild, "some-text-channel", ChannelType.GuildText)
169
286
  ```
170
287
 
171
- - Almost every channel type in discord.js extends `BaseChannel`, so you should be able to pass in whatever channel you need to here.
288
+ Getting a properly typed channel with discord.js can be a bit of a pain, so this is an alternative.
package/dist/bot.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Client, Events, REST } from "discord.js";
2
- import CommandManager from "./command-manager.js";
3
- import EventManager from "./event-manager.js";
2
+ import { CommandManager } from "./command-manager.js";
3
+ import { EventManager } from "./event-manager.js";
4
4
  class Bot {
5
5
  #discord;
6
6
  commands;
@@ -24,5 +24,5 @@ class Bot {
24
24
  await this.#discord.client.login(this.#discord.token);
25
25
  }
26
26
  }
27
- export default Bot;
28
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm90LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2JvdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFpQixNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBQ2hFLE9BQU8sY0FBYyxNQUFNLHNCQUFzQixDQUFBO0FBQ2pELE9BQU8sWUFBWSxNQUFNLG9CQUFvQixDQUFBO0FBZTdDLE1BQU0sR0FBRztJQUNQLFFBQVEsQ0FBZ0I7SUFFZixRQUFRLENBQWdCO0lBQ3hCLE1BQU0sQ0FBYztJQUU3QixZQUFZLE9BQW1CO1FBQzdCLElBQUksQ0FBQyxRQUFRLEdBQUc7WUFDZCxhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWE7WUFDcEMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1lBQ3BCLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDO1lBQ3pDLElBQUksRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDO1NBQ3pDLENBQUE7UUFFRCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUNqRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQTtJQUMvQyxDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxHQUFHLEVBQUU7WUFDakQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFBO1FBQ2pDLENBQUMsQ0FBQyxDQUFBO1FBRUYsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtRQUN2QixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ3JCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDdkQsQ0FBQztDQUNGO0FBRUQsZUFBZSxHQUFHLENBQUEifQ==
27
+ export { Bot };
28
+ //# sourceMappingURL=bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAsB,MAAM,YAAY,CAAA;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAejD,MAAM,GAAG;IACE,QAAQ,CAAgB;IAEjB,QAAQ,CAAgB;IACxB,MAAM,CAAc;IAEpC,YAAmB,OAAmB;QACpC,IAAI,CAAC,QAAQ,GAAG;YACd,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;YACzC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;SACzC,CAAA;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACjD,IAAI,CAAC,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/C,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,GAAG,EAAE;YACjD,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QACvB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;QACrB,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC;CACF;AAED,OAAO,EAAE,GAAG,EAAE,CAAA"}
@@ -1,8 +1,8 @@
1
1
  import { Collection, Events, Routes, } from "discord.js";
2
- import { UserError } from "./util.js";
2
+ import { throwUserError, UserError } from "./util.js";
3
3
  class CommandManager {
4
4
  #commands = new Collection();
5
- #globalPreRunHook;
5
+ #globalCommandHook;
6
6
  #discord;
7
7
  constructor(discord) {
8
8
  this.#discord = discord;
@@ -13,24 +13,20 @@ class CommandManager {
13
13
  add(command) {
14
14
  this.#commands.set(command.command.name, command);
15
15
  }
16
- setGlobalPreRunHook(hook) {
17
- this.#globalPreRunHook = hook;
16
+ setGlobalCommandHook(commandHook) {
17
+ this.#globalCommandHook = commandHook;
18
18
  }
19
19
  async register() {
20
20
  const payload = this.#commands.map((c) => c.command);
21
21
  const route = Routes.applicationCommands(this.#discord.applicationId);
22
22
  await this.#discord.rest.put(route, { body: payload });
23
- console.log(`Registered ${this.#commands.size} (/) commands.`);
23
+ console.log(`Registered ${this.#commands.size.toString()} (/) commands.`);
24
24
  }
25
25
  async unregisterGuildCommands() {
26
- if (this.#discord.client.readyAt) {
27
- await this._unregisterGuildCommands().catch(console.error);
28
- }
29
- else {
30
- this.#discord.client.once(Events.ClientReady, async () => {
31
- await this._unregisterGuildCommands().catch(console.error);
32
- });
33
- }
26
+ if (this.#discord.client.readyAt)
27
+ await this._unregisterGuildCommands();
28
+ else
29
+ this.#discord.client.once(Events.ClientReady, () => void this._unregisterGuildCommands());
34
30
  }
35
31
  async _unregisterGuildCommands() {
36
32
  let guilds;
@@ -41,11 +37,16 @@ class CommandManager {
41
37
  console.error("Unable to unregister guild commands. Failed to fetch guilds.");
42
38
  throw error;
43
39
  }
40
+ const unregisterPromises = [];
44
41
  for (const guild of guilds.values()) {
45
42
  const route = Routes.applicationGuildCommands(this.#discord.applicationId, guild.id);
46
- await this.#discord.rest.put(route, { body: [] });
47
- console.log(`Unregistered commands from guild: ${guild.name}`);
43
+ const unregisterGuildCommands = async () => {
44
+ await this.#discord.rest.put(route, { body: [] });
45
+ console.log(`Unregistered commands from guild: ${guild.name}`);
46
+ };
47
+ unregisterPromises.push(unregisterGuildCommands());
48
48
  }
49
+ await Promise.all(unregisterPromises);
49
50
  }
50
51
  async unregisterApplicationCommands() {
51
52
  const route = Routes.applicationCommands(this.#discord.applicationId);
@@ -53,7 +54,7 @@ class CommandManager {
53
54
  console.log("Unregistered application commands.");
54
55
  }
55
56
  _listen() {
56
- this.#discord.client.on(Events.InteractionCreate, async (interaction) => {
57
+ const listen = async (interaction) => {
57
58
  if (!interaction.isChatInputCommand())
58
59
  return;
59
60
  if (!interaction.guildId)
@@ -61,31 +62,32 @@ class CommandManager {
61
62
  if (!interaction.inCachedGuild())
62
63
  await interaction.client.guilds.fetch(interaction.guildId).catch(console.error);
63
64
  if (!interaction.inCachedGuild()) {
64
- this.interactionReply(interaction, "Guild is not cached. Try again.");
65
+ CommandManager.interactionReply(interaction, "Guild is not cached. Try again.");
65
66
  return;
66
67
  }
67
68
  const command = this.#commands.get(interaction.commandName);
68
69
  if (!command) {
69
- this.interactionReply(interaction, `Failed to get command with name: ${interaction.commandName}`);
70
+ CommandManager.interactionReply(interaction, `Failed to get command with name: ${interaction.commandName}`);
70
71
  return;
71
72
  }
72
- if (!(await this.checkRoles(command, interaction))) {
73
- this.interactionReply(interaction, "You do not have one of the required roles to run this command.");
73
+ if (!(await CommandManager.checkRoles(command, interaction))) {
74
+ CommandManager.interactionReply(interaction, "You do not have one of the required roles to run this command.");
74
75
  return;
75
76
  }
76
77
  try {
77
- const shouldContinue = this.#globalPreRunHook ? await this.#globalPreRunHook(interaction) : true;
78
+ const shouldContinue = this.#globalCommandHook ? await this.#globalCommandHook(interaction) : true;
78
79
  if (!shouldContinue)
79
- return;
80
+ throwUserError("The global command hook returned false.");
80
81
  await command.run(interaction);
81
82
  }
82
83
  catch (error) {
83
- this.interactionReply(interaction, error);
84
+ CommandManager.interactionReply(interaction, error);
84
85
  }
85
- });
86
+ };
87
+ this.#discord.client.on(Events.InteractionCreate, (interaction) => void listen(interaction));
86
88
  console.log("Listening for commands.");
87
89
  }
88
- async checkRoles(command, interaction) {
90
+ static async checkRoles(command, interaction) {
89
91
  if (!command.requiredRoles)
90
92
  return true;
91
93
  if (command.requiredRoles.length > 0) {
@@ -96,8 +98,8 @@ class CommandManager {
96
98
  }
97
99
  return false;
98
100
  }
99
- interactionReply(interaction, error) {
100
- let errorMessage = "";
101
+ static interactionReply(interaction, error) {
102
+ let errorMessage;
101
103
  if (error instanceof UserError)
102
104
  errorMessage = error.message;
103
105
  else if (error instanceof Error && error.stack)
@@ -105,10 +107,13 @@ class CommandManager {
105
107
  else
106
108
  errorMessage = String(error);
107
109
  const message = `There was an error while running this command.\n\`\`\`${errorMessage}\`\`\``;
108
- interaction.deferred
109
- ? void interaction.editReply(message).catch(console.error)
110
- : void interaction.reply({ content: message, ephemeral: true }).catch(console.error);
110
+ const handleInteractionReply = async () => {
111
+ await (interaction.deferred
112
+ ? interaction.editReply(message).catch(console.error)
113
+ : interaction.reply({ content: message, ephemeral: true }).catch(console.error));
114
+ };
115
+ void handleInteractionReply();
111
116
  }
112
117
  }
113
- export default CommandManager;
114
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWFuZC1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbW1hbmQtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsVUFBVSxFQUNWLE1BQU0sRUFFTixNQUFNLEdBQ1AsTUFBTSxZQUFZLENBQUE7QUFFbkIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQVVyQyxNQUFNLGNBQWM7SUFDbEIsU0FBUyxHQUFHLElBQUksVUFBVSxFQUFtQixDQUFBO0lBQzdDLGlCQUFpQixDQUFjO0lBQy9CLFFBQVEsQ0FBZ0I7SUFFeEIsWUFBWSxPQUF1QjtRQUNqQyxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQTtJQUN6QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxHQUFHLENBQUMsT0FBZ0I7UUFDbEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFDbkQsQ0FBQztJQUVELG1CQUFtQixDQUFDLElBQWlCO1FBQ25DLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUE7SUFDL0IsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRO1FBQ1osTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUNwRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQTtRQUNyRSxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQTtRQUV0RCxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsSUFBSSxD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
118
+ export { CommandManager };
119
+ //# sourceMappingURL=command-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-manager.js","sourceRoot":"","sources":["../src/command-manager.ts"],"names":[],"mappings":"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"}
@@ -12,12 +12,20 @@ class EventManager {
12
12
  }
13
13
  _listen() {
14
14
  for (const event of this.#events) {
15
- this.#discord.client.on(event.event, async (...args) => {
16
- await event.handler(this.#discord.client, ...args).catch(console.error);
17
- });
15
+ const listen = async (...args) => {
16
+ try {
17
+ // TS Error: Expression produces a union type that is too complex to represent.
18
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
19
+ await event.handler(this.#discord.client, ...args);
20
+ }
21
+ catch (error) {
22
+ console.error(error);
23
+ }
24
+ };
25
+ this.#discord.client.on(event.event, (...args) => void listen(...args));
18
26
  }
19
- console.log(`Listening for (${this.#events.length}) events.`);
27
+ console.log(`Listening for (${this.#events.length.toString()}) events.`);
20
28
  }
21
29
  }
22
- export default EventManager;
23
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnQtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ldmVudC1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWdCQSxNQUFNLFlBQVk7SUFDaEIsT0FBTyxHQUFrQixFQUFFLENBQUE7SUFDM0IsUUFBUSxDQUFnQjtJQUV4QixZQUFZLE9BQXVCO1FBQ2pDLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFBO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILEdBQUcsQ0FBd0IsS0FBcUI7UUFDOUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDMUIsQ0FBQztJQUVELE9BQU87UUFDTCxLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDaEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxFQUFFLEVBQUU7Z0JBQ3JELE1BQU8sS0FBSyxDQUFDLE9BQXdCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQzNGLENBQUMsQ0FBQyxDQUFBO1NBQ0g7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sV0FBVyxDQUFDLENBQUE7SUFDL0QsQ0FBQztDQUNGO0FBTUQsZUFBZSxZQUFZLENBQUEifQ==
30
+ export { EventManager };
31
+ //# sourceMappingURL=event-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-manager.js","sourceRoot":"","sources":["../src/event-manager.ts"],"names":[],"mappings":"AAoBA,MAAM,YAAY;IACP,OAAO,GAAkB,EAAE,CAAA;IAC3B,QAAQ,CAAgB;IAEjC,YAAmB,OAAuB;QACxC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;IACzB,CAAC;IAED;;OAEG;IACI,GAAG,CAAwB,KAAqB;QACrD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAEM,OAAO;QACZ,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,KAAK,EAAE,GAAG,IAAsC,EAAE,EAAE;gBACjE,IAAI,CAAC;oBACH,+EAA+E;oBAC/E,uEAAuE;oBACvE,MAAO,KAAK,CAAC,OAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;gBACtE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;gBACtB,CAAC;YACH,CAAC,CAAA;YAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAA;QACzE,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;IAC1E,CAAC;CACF;AAMD,OAAO,EAAE,YAAY,EAAE,CAAA"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { default } from "./bot.js";
1
+ export { Bot } from "./bot.js";
2
2
  export { getChannel, throwError, throwUserError } from "./util.js";
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUdsQyxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsTUFBTSxXQUFXLENBQUEifQ==
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAG9B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA"}
@@ -1,6 +1,6 @@
1
- import { Client, ClientOptions, REST } from "discord.js";
2
- import CommandManager from "./command-manager.js";
3
- import EventManager from "./event-manager.js";
1
+ import { Client, REST, type ClientOptions } from "discord.js";
2
+ import { CommandManager } from "./command-manager.js";
3
+ import { EventManager } from "./event-manager.js";
4
4
  interface BotOptions {
5
5
  applicationId: string;
6
6
  token: string;
@@ -19,5 +19,5 @@ declare class Bot {
19
19
  constructor(options: BotOptions);
20
20
  login(): Promise<void>;
21
21
  }
22
- export default Bot;
22
+ export { Bot };
23
23
  export type { BotOptions, DiscordContext };
@@ -1,23 +1,23 @@
1
- import { ChatInputCommandInteraction, RESTPostAPIChatInputApplicationCommandsJSONBody } from "discord.js";
2
- import { DiscordContext } from "./bot.js";
1
+ import { type ChatInputCommandInteraction, type RESTPostAPIChatInputApplicationCommandsJSONBody } from "discord.js";
2
+ import type { DiscordContext } from "./bot.js";
3
3
  interface Command {
4
4
  requiredRoles?: string[];
5
5
  command: RESTPostAPIChatInputApplicationCommandsJSONBody;
6
6
  run: (interaction: ChatInputCommandInteraction<"cached">) => void | Promise<void>;
7
7
  }
8
- type CommandHook = (interaction: ChatInputCommandInteraction<"cached">) => Promise<boolean>;
8
+ type CommandHook = (interaction: ChatInputCommandInteraction<"cached">) => boolean | Promise<boolean>;
9
9
  declare class CommandManager {
10
10
  #private;
11
11
  constructor(discord: DiscordContext);
12
12
  add(command: Command): void;
13
- setGlobalPreRunHook(hook: CommandHook): void;
13
+ setGlobalCommandHook(commandHook: CommandHook): void;
14
14
  register(): Promise<void>;
15
15
  unregisterGuildCommands(): Promise<void>;
16
16
  private _unregisterGuildCommands;
17
17
  unregisterApplicationCommands(): Promise<void>;
18
18
  _listen(): void;
19
- private checkRoles;
20
- private interactionReply;
19
+ private static checkRoles;
20
+ private static interactionReply;
21
21
  }
22
- export default CommandManager;
22
+ export { CommandManager };
23
23
  export type { Command, CommandHook };
@@ -1,7 +1,7 @@
1
- import { Client, ClientEvents, Events } from "discord.js";
2
- import { DiscordContext } from "./bot.js";
3
- type ValidEvents = Exclude<Events, Events.VoiceServerUpdate | Events.Raw>;
4
- type EventHandler<E extends ValidEvents = ValidEvents> = (client: Client, ...args: ClientEvents[E]) => Promise<void>;
1
+ import type { Client, ClientEvents } from "discord.js";
2
+ import type { DiscordContext } from "./bot.js";
3
+ type ValidEvents = keyof ClientEvents;
4
+ type EventHandler<E extends ValidEvents = ValidEvents> = (client: Client, ...args: ClientEvents[E]) => void | Promise<void>;
5
5
  type EventHandlerMap = {
6
6
  [E in ValidEvents]: EventHandler<E>;
7
7
  };
@@ -18,5 +18,5 @@ declare class EventManager {
18
18
  type Event = {
19
19
  [E in ValidEvents]: SingleEvent<E>;
20
20
  }[ValidEvents];
21
- export default EventManager;
21
+ export { EventManager };
22
22
  export type { Event };
@@ -1,4 +1,4 @@
1
- export { default } from "./bot.js";
1
+ export { Bot } from "./bot.js";
2
2
  export type { Command, CommandHook } from "./command-manager.js";
3
3
  export type { Event } from "./event-manager.js";
4
4
  export { getChannel, throwError, throwUserError } from "./util.js";
@@ -1,4 +1,4 @@
1
- import { CategoryChannel, ChannelType, ForumChannel, Guild, NewsChannel, StageChannel, TextChannel, VoiceChannel } from "discord.js";
1
+ import type { CategoryChannel, ChannelType, ForumChannel, Guild, NewsChannel, StageChannel, TextChannel, VoiceChannel } from "discord.js";
2
2
  interface ChannelTypeToChannelMap {
3
3
  [ChannelType.GuildCategory]: CategoryChannel;
4
4
  [ChannelType.GuildAnnouncement]: NewsChannel;
@@ -7,9 +7,39 @@ interface ChannelTypeToChannelMap {
7
7
  [ChannelType.GuildVoice]: VoiceChannel;
8
8
  [ChannelType.GuildForum]: ForumChannel;
9
9
  }
10
+ /**
11
+ * Returns the guild channel of the given name/ID and type, otherwise throws.
12
+ *
13
+ * @param guild The Guild to fetch the channel from
14
+ * @param channelNameOrId The name or ID of the channel to fetch
15
+ * @param channelType The type of channel to fetch
16
+ * @returns The channel of the given name/ID and type
17
+ * @example
18
+ * ```ts
19
+ * import { getChannel } from "discord-bot-shared"
20
+ * import { ChannelType } from "discord.js"
21
+ *
22
+ * // guild is of type Guild from discord.js
23
+ * const someTextChannel = await getChannel(guild, "some-text-channel", ChannelType.GuildText)
24
+ * ```
25
+ *
26
+ * Getting a properly typed channel with discord.js can be a bit of a pain, so this is an alternative.
27
+ */
10
28
  declare function getChannel<T extends keyof ChannelTypeToChannelMap>(guild: Guild, channelNameOrId: string, channelType: T): Promise<ChannelTypeToChannelMap[T]>;
11
- declare function throwError(error: string): never;
12
- declare function throwUserError(error: string): never;
29
+ /**
30
+ * Throws an error with the given message.
31
+ *
32
+ * @param message The message to throw
33
+ * @throws Error
34
+ */
35
+ declare function throwError(message: string): never;
36
+ /**
37
+ * Throws a UserError with the given message.
38
+ *
39
+ * @param message The message to throw
40
+ * @throws UserError
41
+ */
42
+ declare function throwUserError(message: string): never;
13
43
  declare class UserError extends Error {
14
44
  constructor(message: string);
15
45
  }
package/dist/util.js CHANGED
@@ -1,27 +1,58 @@
1
- import { ChannelType, } from "discord.js";
1
+ /**
2
+ * Returns the guild channel of the given name/ID and type, otherwise throws.
3
+ *
4
+ * @param guild The Guild to fetch the channel from
5
+ * @param channelNameOrId The name or ID of the channel to fetch
6
+ * @param channelType The type of channel to fetch
7
+ * @returns The channel of the given name/ID and type
8
+ * @example
9
+ * ```ts
10
+ * import { getChannel } from "discord-bot-shared"
11
+ * import { ChannelType } from "discord.js"
12
+ *
13
+ * // guild is of type Guild from discord.js
14
+ * const someTextChannel = await getChannel(guild, "some-text-channel", ChannelType.GuildText)
15
+ * ```
16
+ *
17
+ * Getting a properly typed channel with discord.js can be a bit of a pain, so this is an alternative.
18
+ */
2
19
  async function getChannel(guild, channelNameOrId, channelType) {
3
20
  const channels = await guild.channels.fetch();
4
21
  let channel;
5
- channel = channels.find((channel) => (channel ? channel.name === channelNameOrId : false));
22
+ channel = channels.find((chan) => (chan ? chan.name === channelNameOrId : false));
23
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
6
24
  if (channel && channel.type === channelType)
7
25
  return channel;
8
26
  channel = channels.get(channelNameOrId);
27
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
9
28
  if (channel && channel.type === channelType)
10
29
  return channel;
11
30
  throwError(`Failed to get channel: ${channelNameOrId}`);
12
31
  }
13
- function throwError(error) {
14
- throw new Error(error);
32
+ /**
33
+ * Throws an error with the given message.
34
+ *
35
+ * @param message The message to throw
36
+ * @throws Error
37
+ */
38
+ function throwError(message) {
39
+ throw new Error(message);
15
40
  }
16
- function throwUserError(error) {
17
- throw new UserError(error);
41
+ /**
42
+ * Throws a UserError with the given message.
43
+ *
44
+ * @param message The message to throw
45
+ * @throws UserError
46
+ */
47
+ function throwUserError(message) {
48
+ throw new UserError(message);
18
49
  }
19
50
  class UserError extends Error {
20
51
  constructor(message) {
21
52
  super(message);
22
- this.name = this.constructor.name;
53
+ this.name = "UserError";
23
54
  Object.setPrototypeOf(this, new.target.prototype);
24
55
  }
25
56
  }
26
57
  export { UserError, getChannel, throwError, throwUserError };
27
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy91dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFFTCxXQUFXLEdBUVosTUFBTSxZQUFZLENBQUE7QUFXbkIsS0FBSyxVQUFVLFVBQVUsQ0FDdkIsS0FBWSxFQUNaLGVBQXVCLEVBQ3ZCLFdBQWM7SUFFZCxNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUE7SUFFN0MsSUFBSSxPQUFzRCxDQUFBO0lBQzFELE9BQU8sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksS0FBSyxlQUFlLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7SUFDMUYsSUFBSSxPQUFPLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxXQUFXO1FBQUUsT0FBTyxPQUFxQyxDQUFBO0lBRXpGLE9BQU8sR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0lBQ3ZDLElBQUksT0FBTyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssV0FBVztRQUFFLE9BQU8sT0FBcUMsQ0FBQTtJQUV6RixVQUFVLENBQUMsMEJBQTBCLGVBQWUsRUFBRSxDQUFDLENBQUE7QUFDekQsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLEtBQWE7SUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUN4QixDQUFDO0FBRUQsU0FBUyxjQUFjLENBQUMsS0FBYTtJQUNuQyxNQUFNLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFBO0FBQzVCLENBQUM7QUFFRCxNQUFNLFNBQVUsU0FBUSxLQUFLO0lBQzNCLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDZCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFBO1FBRWpDLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUE7SUFDbkQsQ0FBQztDQUNGO0FBRUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxDQUFBIn0=
58
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;GAiBG;AACH,KAAK,UAAU,UAAU,CACvB,KAAY,EACZ,eAAuB,EACvB,WAAc;IAEd,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;IAE7C,IAAI,OAAsD,CAAA;IAC1D,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IACjF,uEAAuE;IACvE,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,OAAqC,CAAA;IAEzF,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IACvC,uEAAuE;IACvE,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,OAAqC,CAAA;IAEzF,UAAU,CAAC,0BAA0B,eAAe,EAAE,CAAC,CAAA;AACzD,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,OAAe;IACjC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,OAAe;IACrC,MAAM,IAAI,SAAS,CAAC,OAAO,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,SAAU,SAAQ,KAAK;IAC3B,YAAmB,OAAe;QAChC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;QAEvB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACnD,CAAC;CACF;AAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,CAAA"}
package/package.json CHANGED
@@ -1,40 +1,47 @@
1
1
  {
2
2
  "name": "discord-bot-shared",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "description": "Modules for creating discord bots.",
6
- "repository": "github:adamhl8/discord-bot-shared",
7
- "author": "adamhl8",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/adamhl8/discord-bot-shared"
9
+ },
10
+ "homepage": "https://github.com/adamhl8/discord-bot-shared",
11
+ "bugs": {
12
+ "url": "https://github.com/adamhl8/discord-bot-shared/issues"
13
+ },
14
+ "author": {
15
+ "email": "adamhl@pm.me",
16
+ "name": "Adam Langbert",
17
+ "url": "https://github.com/adamhl8"
18
+ },
8
19
  "license": "MIT",
9
- "main": "dist/index.js",
10
- "types": "dist/types/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "import": "./dist/index.js",
23
+ "types": "./dist/types/index.d.ts"
24
+ }
25
+ },
11
26
  "files": [
12
- "dist/",
13
- "README.md",
14
- "LICENSE"
27
+ "dist/"
15
28
  ],
29
+ "scripts": {
30
+ "bundle": "bun lint && rm -rf ./dist && tsc -p ./tsconfig.build.json",
31
+ "lint": "tsc --noEmit && prettier --write . && eslint .",
32
+ "prepare": "find .githooks -type f -exec ln -srf {} .git/hooks/ \\;",
33
+ "prepublish": "bun bundle"
34
+ },
16
35
  "peerDependencies": {
17
36
  "discord.js": "^14.0.0"
18
37
  },
19
38
  "devDependencies": {
20
- "@types/node": "^20.6.2",
21
- "@typescript-eslint/eslint-plugin": "^6.7.0",
22
- "@typescript-eslint/parser": "^6.7.0",
23
- "discord.js": "^14.13.0",
24
- "eslint": "^8.49.0",
25
- "eslint-config-prettier": "^9.0.0",
26
- "eslint-plugin-sonarjs": "^0.21.0",
27
- "eslint-plugin-unicorn": "^48.0.1",
28
- "prettier": "^3.0.3",
29
- "prettier-plugin-organize-imports": "^3.2.3",
30
- "prettier-plugin-pkg": "^0.18.0",
31
- "prettier-plugin-sh": "^0.13.1",
32
- "typescript": "^5.2.2"
33
- },
34
- "scripts": {
35
- "build": "rm -rf dist && tsc",
36
- "format": "prettier --write .",
37
- "lint": "eslint ./src/",
38
- "prepublish": "pnpm build"
39
+ "@types/bun": "^1.2.17",
40
+ "discord.js": "^14.20.0",
41
+ "eslint": "^9.29.0",
42
+ "eslint-config-builder": "^0.21.2",
43
+ "prettier": "^3.6.1",
44
+ "typescript": "^5.8.3",
45
+ "typescript-eslint": "^8.35.0"
39
46
  }
40
- }
47
+ }