yungkaiworldbot
所属分类:collect
开发工具:TypeScript
文件大小:0KB
下载次数:0
上传日期:2024-01-31 07:33:23
上 传 者:
sh-1993
说明: 永凯世界的仲裁和杂项机器人,音乐艺术家永凯的不和服务器!
(Moderation & misc bot for yung kai world, the Discord server for the music artist yung kai!)
文件列表:
scripts/
src/
tests/
.env.example
.eslintrc.json
jest.config.ts
package-lock.json
package.json
tsconfig.build.json
tsconfig.json
# yung kai world's TempBot
Misc bot for **yung kai world**, the Discord server for the music artist [yung
kai](https://linktr.ee/yungkaiboy)!
## Overview
The iconic **@TempBot** lurks in the channels, always ready to ~~annoy~~ bring
some humor or personality to the server with stupid Dad jokes, entertaining your
different catchphrases, and more! Now complete with timeout permissions.
**:nekocatshrug:**
This started as a throwaway for-fun project, hence the name "TempBot", but the
name stuck. This codebase is an ongoing project welcome to requests and
suggestions. Server members are welcome to contribute by requesting features,
reporting bugs, or opening pull request/issues! You can also communicate your
requests or receive periodic notifications about new features in the [TempBot
feature requests
thread](https://discord.com/channels/1101561213663580190/1181497697560186961).
## Setup
### Local Setup
Prerequisites:
* [Node.js](https://nodejs.org/) v16+
* [npm](https://www.npmjs.com/) v9+
```sj
node --version
npm --version
```
Clone the repository if you haven't:
```sh
git clone https://github.com/vinlin24/yungkaiworldbot
cd yungkaiworldbot
```
Install dependencies:
```sh
npm install
```
### Environment File
For the bot to function properly, you need to create and populate the
environment file. Some environment variables are highly sensitive (such as the
bot token), so this file is deliberately [.gitignore](.gitignore)d and must be
manually regenerated.
An [.env.example](.env.example) is provided as a skeleton for the required
**.env** file:
```sh
cp .env.example .env
```
Consult the documentation at [env.d.ts](src/types/env.d.ts) for a description of
each key and possibly where to find them to fill out the redacted values.
Contact any of the bot developers for any values you need help with or the
values for the production version of the bot.
For Discord IDs, you should enable **Developer Mode** to be able to conveniently
copy IDs from the right-click context menus of servers, channels, roles, users,
etc. To enable it, go to **User Settings > Advanced > Developer Mode**.
For variables names, we use this suffix convention:
* `_GID`: Guild ID. Servers are referred to as "guilds" in the Discord API.
* `_CID`: Channel ID. This can be any type of channel (text, voice, etc.).
* `_RID`: Role ID. This is useful for role-based features. It is also the basis
of this bot's [privilege system](src/middleware/privilege.middleware.ts).
* `_UID`: User ID. This is useful for user-based features (to give the bot a
little personality, basically).
GIDs, CIDs, and RIDs can be hard-coded into [config.ts](src/config.ts). UIDs
should be environment variables.
> :warning: **NON-BOT USER IDs SHOULD BE REDACTED IN VERSION CONTROL.**
>
> While Discord IDs in general are only used internally by Discord's API,
> [Discord themselves](https://discord.com/safety/confidentiality-in-moderation)
> stated that **user IDs** should be considered personally identifiable
> information (PII). Because this bot is open-source, we want to prevent any
> chance of PII leak or doxing.
>
> On a related note, use your common sense when naming user ID keys. Use
> nicknames or "gamer aliases" where possible. Do not use full or legal names
> under any circumstances.
## Running
### package.json Scripts
| Shell Command | Description |
| ------------------ | -------------------------------------------------------------------------------------------- |
| `npm run dev` | Start the bot runtime. This interprets the TypeScript source directly for fastest startup. |
| `npm run sync` | Deploy application commands to Discord's backend. This does not start the bot runtime. |
| `npm run clean` | Clear JavaScript build files. |
| `npm run build` | Compile TypeScript source to JavaScript. |
| `npm start` | Start the bot runtime. This invokes Node.js on the compiled JavaScript ready for production. |
| `npm run silent` | Same as `npm run dev` but disable custom listeners. |
| `npm run now` | Run existing JavaScript build files right away. |
| `npm test` | Run tests. |
| `npm run lint` | Run the linter to report errors/warnings. |
| `npm run lint:fix` | Run the linter and fix all fixable errors in-place. |
### Command Registration vs. Bot Runtime
Application (slash) commands have to be explicitly registered with Discord for
them to show up in the commands pop-up on the Discord application (and thus be
able to be used). They should also be redeployed every time the *definition* of
the command changes (description, options, etc.).
There is a daily limit on application command creation, so it doesn't make sense
to automate this into the main bot runtime (such as on the "ready" event). The
program thus separates the two modes through command line flags:
* Synchronize slash command definitions with Discord's backend (bot itself
doesn't come online):
```sh
# npm run sync
node dist/index.js --sync
```
* Start the bot runtime (log in to Discord and listen for commands and events):
```sh
# npm start
node dist/index.js
```
The [discord.js
Guide](https://discordjs.guide/creating-your-bot/command-deployment.html#command-registration)
explains well the rationale behind this kind of separation.
Your flow would look something like:
1. Define/update a command definition in source code.
2. Deploy the command with `--sync`.
3. Start the bot runtime to see it in action.
4. Changes to the code that don't modify command definitions can skip Step 2.
## Project Architecture
**This codebase uses the [discord.js](https://discord.js.org/#/) framework for
creating the Discord bot.**
The directory structure loosely resembles the pattern recommended in the
[discord.js Guide](https://discordjs.guide/) in that commands and events are
defined one-per-file and then dynamically discovered and loaded at runtime.
However, I also got a bit carried away defining a sort of
framework-within-a-framework on top of discord.js to further streamline adding
new commands and event listeners. This behind-the-scenes work is under
[bot/](src/bot/) and shouldn't need to be touched outside of project-wide
refactoring.
Notably, I initially took inspiration from how
[Express.js](https://expressjs.com/) uses a builder-like pattern to register
callbacks on some handler class, as well as the support for reusable middleware
that offloads the burden of data validation from the main command/event listener
callback.
I chose to liken the project structure to the typical
middleware-controller-service layer design from backend REST API architecture:
* Modules implementing the main logic for handling commands and event listeners
are collectively referred to as "[controllers](src/controllers/)". Start here
if you want to get up and running with adding a new command/event listener,
and reference any of the existing modules as examples of the required file
anatomy.
* Checks and filters for the commands and event listeners respectively are
analogous to "[middleware](src/middleware/)".
* Complex state management can be encapsulated within
"[services](src/services/)", serving as the single source of truth for
stateful data or as clients for 3rd party APIs.
* TypeScript-related utilities or helper classes/abstract classes/interfaces are
under [types/](src/types/).
* Project-wide utility functions are under [utils/](src/utils/).
My main goal with this is to promote code reusability and modularity, also
making it easier to test the modules through a code mocking framework (we use
[Jest](https://jestjs.io/)) instead of having to go through the real Discord API
and spamming commands/messages on the real server.
### Commands
Command modules should be created anywhere under
[controllers/](src/controllers/) and end with `.controller.ts` to be discovered
and loaded by our [dynamic command loader](src/bot/command.loader.ts) on bot
startup. The module *must* export a `CommandSpec` object, but I've defined a
`CommandBuilder` helper class to make building this object more convenient and
readable.
Refer to the [`CommandSpec`](src/types/command.types.ts) type for documentation
on the different parts of a command to expose per module. At a high-level, a
command contains zero or more **checks**, which are like middleware determining
whether the main callback should run, followed by the main `execute` controller.
#### Command Lifecycle
0. Command is deployed to Discord via REST API (using a special [command line
switch](#packagejson-scripts)).
1. User enters a slash command on the Discord application.
2. Command is forwarded from Discord server to discord.js runtime, which
encapsulates the context as a `ChatInputCommandInteraction` object and emits
it with an `interactionCreate` event.
3. `interactionCreate` event is received by a [special event
listener*](src/bot/listeners/command.listener.ts) on our `BotClient` class,
which dispatches the correct `CommandRunner` to handle it.
4. `CommandRunner` executes the [command pipeline](#command-execution-pipeline)
defined by the `CommandSpec` with which it was initialized.
*Note that commands are really just a special form of event,
`interactionCreate`.*
#### Command Execution Pipeline
From [command.runner.ts](src/bot/command.runner.ts):
```ts
/**
* COMMAND EXECUTION PIPELINE
* --------------------------
* Checks: run predicate
* -> success: move onto Execute
* -> fail: run onFail if provided, short-circuit
* -> error: handleCommandError, short-circuit
* -> error: handleCommandError, short-circuit
* Execute: run execute
* -> success: move onto Cleanup
* -> error: handleCommandError, return
* Cleanup: run all afterExecute hooks of checks
* -> success: return
* -> error: handleCommandError, DON'T short-circuit
*/
```
### Event Listeners
Event listener modules should be created anywhere under
[controllers/](src/controllers/) and end with `.listener.ts` to be discovered,
loaded, and registered on our bot by our [dynamic listener
loader](src/bot/listener.loader.ts) on bot startup. The module *must* export a
`ListenerSpec` object, but I've defined a `ListenerBuilder` helper class to make
building this object more convenient and readable.
Refer to the [`ListenerSpec`](src/types/listener.types.ts) type for
documentation on the different parts of a listener to expose per module. At a
high-level, a listener contains zero or more **filters**, which are like
middleware determining whether the main callback should run, followed by the
main `execute` controller.
Note that because of the immense popularity of the
`ListenerSpec` specialization, there also exists a
`MessageListenerBuilder` helper. Notably, this adds support for a **cooldown**
mechanism, which has become very popular with requests.
#### Event Lifecycle
1. An event occurs on the Discord server.
2. Event is sent to our `BotClient` running under the discord.js runtime, which
makes the bot emit the event.
3. The emitted event is received by all callbacks registered to receive it.
These callbacks are the entry point into the `ListenerRunner`.
4. `ListenerRunner` executes the [listener
pipeline](#listener-execution-pipeline) defined by the `ListenerSpec` with
which it was initialized.
#### Listener Execution Pipeline
From [listener.runner.ts](src/bot/listener.runner.ts):
```ts
/**
* LISTENER EXECUTION PIPELINE
* ---------------------------
* Filters: run predicate
* -> success: move onto Execute
* -> fail: run onFail if provided, short-circuit
* -> error: handleListenerError, short-circuit
* -> error: handleListenerError, short-circuit
* Execute: run execute
* -> success: move onto Cleanup
* -> error: handleListenerError, return
* Cleanup: run all afterExecute hooks of filters
* -> success: return
* -> error: handleListenerError, DON'T short-circuit
*/
```
### Database
This bot uses [MongoDB](https://www.mongodb.com/) for persistent storage. You
can use this script to connect to the MongoDB cluster:
```sh
scripts/db-connect.sh
```
This automatically loads the [.env](#environment-file) file and uses the
`DB_CONN_STRING` to connect to the cluster.
近期下载者:
相关文件:
收藏者: