First off, thank you for considering contributing to Jasper! It’s people like you that make Jasper such a great tool.
If you encounter any bugs, please open an issue on GitHub with detailed information about the bug and how to reproduce it. Include any relevant logs and screenshots to help us diagnose the problem.
If you have an idea to enhance Jasper, feel free to open an issue on GitHub with detailed information about the enhancement. Describe the problem you’re trying to solve and how your enhancement will help.
-
Fork the Repository: Click the "Fork" button at the top-right corner of the repository page.
-
Clone the Repository:
git clone https://github.com/your-username/jasper.git cd jasper
-
Install Dependencies:
yarn install
-
Create a Branch: Create a new branch for your feature or bugfix.
git checkout -b feature/your-feature-name
-
Make Changes: Implement your changes. Make sure your code follows the existing code style and conventions.
-
Commit Changes: Commit your changes with a meaningful commit message.
git add . git commit -m "Add a meaningful commit message"
-
Push Changes: Push your changes to your fork.
git push origin feature/your-feature-name
-
Open a Pull Request: Go to the original repository and open a pull request. Provide a detailed description of your changes and link any relevant issues.
Create a .env
file in the root directory with these required environment variables:
BOTID=
PUBLICKEY=
TOKEN=
MONGODB=
PREFIX=
GUILD_ONLY_COMMANDS=1 # 1 = true 0 = false
GUILD_ONLY_COMMANDS_GUILD_ID=
REDISHOST=
REDISPORT=
YOUTUBE_CHANNEL_ID=
YOUTUBE_KEY=
YOUTUBE_KEY_TWO=
YOUTUBE_KEY_THREE=
YOUTUBE_VIDEO_POST_CHANNEL_ID=
YOUTUBE_VIDEO_POST_TIMER=
YOUTUBE_VIDEO_DISCUSSIONS_ROLE_ID=
YOUTUBE_VIDEO_POST_UPDATE=1 # 1 = true 0 = false
SLOWMODE=1 # 1 = true 0 = false
SLOWMODE_COOLDOWN=
SLOWMODE_MESSAGE_TIME=
SLOWMODE_MESSAGE_THRESHOLD=
SLOWMODE_RESET_SLOWMODE=
SLOWMODE_RESET_TIME=
The following environment variables have been removed and are no longer supported:
SUPPORT_ROLE
: Role management now handled through commandsADMIN_ROLE
: Role management now handled through commandsSTAFF_ROLE
: Role management now handled through commandsSUPPORT_THREAD
: Support thread functionality removedSLOWMODE_CHANNEL_ID
: Channel management now handled through commands
-
Build: Compile the TypeScript code.
yarn build
-
Start: Start the bot.
yarn start
-
Development: Run build, lint, and start the bot.
yarn dev
-
Lint: Run ESLint to check for linting errors.
yarn eslint
-
Docker Build: Build the Docker image.
yarn builddocker
-
Docker Run: Run the Docker container.
yarn docker
-
Docker Stop: Stop the Docker container.
yarn dockerstop
-
Docker Compose Up: Start services using Docker Compose.
yarn docker-compose
-
Docker Compose Down: Stop services using Docker Compose.
yarn docker-compose-stop
We use ESLint to maintain code quality. Make sure your code passes all linting rules before submitting a pull request.
This section provides detailed information about developing new components for Jasper.
The project follows a modular plugin-based architecture:
Jasper/
├── Common/ # Shared utilities and types
├── Handlers/ # Core command and event handlers
├── Models/ # Database schemas
├── Plugins/ # Plugin modules
│ ├── Core/ # Core bot functionality
│ │ ├── Commands/
│ │ ├── Events/
│ │ └── CorePlugin.ts
│ └── Tags/ # Tag management module
│ ├── Commands/
│ ├── SubCommands/
│ ├── Modals/
│ └── TagsPlugin.ts
└── Services/ # Service layer for database operations
Each plugin should have its own directory under Plugins/
with the following structure:
// MyPlugin/MyPlugin.ts
import { Plugin } from '../../Common/define';
export const MyPlugin: Plugin = {
name: 'MyPlugin',
description: 'Plugin description',
commands: [], // Commands list
events: [], // Optional events list
public_plugin: true, // Visibility flag
};
Commands are created using the defineCommand
helper:
// MyPlugin/Commands/MyCommand.ts
import { Command, defineCommand } from '../../../Common/define';
import { ApplicationCommandType } from '@antibot/interactions';
export const MyCommand = defineCommand({
command: {
type: ApplicationCommandType.CHAT_INPUT,
name: 'mycommand',
description: 'Command description',
},
permissions: [], // Optional Discord permissions
restrictToConfigRoles: [], // Optional configuration roles
on: async (ctx, interaction) => {
// Command logic
},
});
Subcommands provide additional functionality under a main command:
// MyPlugin/SubCommands/MySubCommand.ts
import { defineSubCommand } from '../../../Common/define';
export const MySubCommand = defineSubCommand({
name: 'mysubcommand',
restrictToConfigRoles: [], // Optional configuration roles
handler: async (ctx, interaction) => {
// Subcommand logic
},
autocomplete: async (ctx, interaction) => {
// Optional autocomplete handler
},
});
// Command options for registration
export const commandOptions = {
name: MySubCommand.name,
description: 'Subcommand description',
type: ApplicationCommandOptionType.SUB_COMMAND,
options: [], // Command options/arguments
};
Events handle Discord or custom events:
// MyPlugin/Events/MyEvent.ts
import { defineEvent } from '../../../Common/define';
export const MyEvent = defineEvent({
event: {
name: 'eventName', // Discord event name
once: false, // Whether to run once or listen continuously
},
on: async (event, ctx) => {
// Event handling logic
},
});
For commands requiring user input forms:
// MyPlugin/Modals/MyModal.ts
import { Modal } from '../../../Common/define';
export const MyModal: Modal = {
customId: 'my_modal',
title: 'Modal Title',
fields: [
{
customId: 'field_id',
label: 'Field Label',
style: TextInputStyle.Short,
required: true,
},
],
};
When creating commands that require role-based access:
import { ConfigurationRoles } from '../../../Common/define';
export const MyCommand = defineCommand({
// ... other command options
restrictToConfigRoles: [ConfigurationRoles.AdminRoles, ConfigurationRoles.StaffRoles],
});
-
File Organization
- Keep related functionality together in plugin directories
- Use clear, descriptive filenames
- Export command options separately for registration
-
Command Structure
- Group related commands under a single base command using subcommands
- Use autocomplete where possible for better UX
- Implement proper permission checks
-
Error Handling
- Use try/catch blocks for async operations
- Provide clear error messages to users
- Handle Discord API errors appropriately
-
Type Safety
- Use TypeScript interfaces and types
- Leverage the provided type definitions
- Define clear input/output types for functions
-
Service Layer
- Use services for database operations
- Follow the service pattern for new functionality
- Maintain separation of concerns
-
Testing
- Test commands with various permission levels
- Verify error handling paths
- Test integration with other plugins/services