Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add dynamic example #2974

Merged
merged 8 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions 09-dynamic-guilds/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# editorconfig.org
root = true

[*]
end_of_line = lf
indent_style = tab
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 4
max_line_length = 140

[*.{yaml, yml}]
indent_style = space
indent_size = 2

[*.md]
indent_style = space
trim_trailing_whitespace = false
36 changes: 36 additions & 0 deletions 09-dynamic-guilds/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# compiled output
/dist
/node_modules
yarn.lock
yarn-error.log

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
8 changes: 8 additions & 0 deletions 09-dynamic-guilds/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"parser": "typescript",
"trailingComma": "none",
"singleQuote": true,
"arrowParens": "avoid",
"endOfLine": "auto",
"printWidth": 120
}
3 changes: 3 additions & 0 deletions 09-dynamic-guilds/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 09 - Dynamic Guilds

This is an updated version of an example created by [@WolffParkinson](https://github.com/wolffparkinson). You can find the original example [here](https://github.com/wolffparkinson/necord-playground/tree/dynamic-guilds)
46 changes: 46 additions & 0 deletions 09-dynamic-guilds/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const typescriptEslintEslintPlugin = require("@typescript-eslint/eslint-plugin");
const globals = require("globals");
const tsParser = require("@typescript-eslint/parser");
const js = require("@eslint/js");
const { FlatCompat } = require("@eslint/eslintrc");

const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});

module.exports = [...compat.extends(
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
), {
plugins: {
"@typescript-eslint": typescriptEslintEslintPlugin,
},

languageOptions: {
globals: {
...globals.node,
},

parser: tsParser,
ecmaVersion: 5,
sourceType: "module",

parserOptions: {
project: "tsconfig.json",
},
},

rules: {
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/ban-types": "off",
},

ignores: ["*.config.js"]
}];
37 changes: 37 additions & 0 deletions 09-dynamic-guilds/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "09-dynamic-guilds",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint src/**/*.ts --fix"
},
"dependencies": {
"@nestjs/common": "10.2.0",
"@nestjs/core": "10.2.0",
"discord.js": "14.17.3",
"necord": "6.8.7",
"reflect-metadata": "0.2.1",
"rimraf": "4.1.2",
"rxjs": "7.8.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.10.0",
"@types/node": "18.14.2",
"@typescript-eslint/eslint-plugin": "5.54.0",
"@typescript-eslint/parser": "5.54.0",
"eslint": "9.10.0",
"eslint-config-prettier": "8.6.0",
"eslint-plugin-prettier": "4.2.1",
"globals": "^15.9.0",
"prettier": "2.8.4",
"typescript": "5.7.3"
}
}
18 changes: 18 additions & 0 deletions 09-dynamic-guilds/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Module } from '@nestjs/common';
import { NecordModule } from 'necord';
import { CommandService } from './command.service';
import { DynamicCommand } from './dynamic.command';
import { AppService } from './app.service';
import { SimpleCommand } from './simple.command';

@Module({
imports: [
NecordModule.forRoot({
intents: ['Guilds'],
token: process.env.DISCORD_TOKEN,
skipRegistration: true
})
],
providers: [CommandService, AppService, DynamicCommand, SimpleCommand]
})
export class AppModule {}
12 changes: 12 additions & 0 deletions 09-dynamic-guilds/src/app.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Injectable, Logger } from '@nestjs/common';
import { ContextOf, Ctx, Once } from 'necord';

@Injectable()
export class AppService {
private readonly logger = new Logger(AppService.name);

@Once('ready')
public onReady(@Ctx() [client]: ContextOf<'ready'>) {
this.logger.log(`Bot is ready! Logged in as ${client.user.tag}`);
}
}
50 changes: 50 additions & 0 deletions 09-dynamic-guilds/src/command.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common';
import { CommandsService, ExplorerService, SlashCommandDiscovery, SlashCommandsService, SlashCommand } from 'necord';
import { Client } from 'discord.js';

@Injectable()
export class CommandService implements OnApplicationBootstrap {
private readonly logger = new Logger();

constructor(
private readonly slashCommandService: SlashCommandsService,
private readonly explorerService: ExplorerService<SlashCommandDiscovery>,
private readonly commandService: CommandsService,
private readonly client: Client
) {}

async onApplicationBootstrap() {
this.client.once('ready', async () => {
await this.updateCommandsMeta();
await this.commandService.registerAllCommands()
});
}

// Fetch guild ids from API
async fetchGuildIds() {
return [{ id: 1, name: 'dynamic', guildIds: [process.env.DB_GUILD_ID] }];
}

async updateCommandsMeta() {
this.logger.verbose('Updating metadata for SlashCommands');

const slashCommands = this.explorerService.explore(SlashCommand.KEY);
this.logger.verbose(`${slashCommands.length} SlashCommand (s) explored`);

const db = await this.fetchGuildIds();
for (const command of slashCommands) {
this.slashCommandService.remove(command.getName());
const data = db.find(d => d.name === command.getName());
if (!data) {
this.logger.warn(`No metadata found for SlashCommand : ${command.getName()}`);
this.slashCommandService.add(command);
return;
}

this.logger.verbose(`Updating metadata for SlashCommand : ${command.getName()}`);

command.setGuilds(data.guildIds ?? []);
this.slashCommandService.add(command);
}
}
}
13 changes: 13 additions & 0 deletions 09-dynamic-guilds/src/dynamic.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Injectable } from '@nestjs/common';
import { Ctx, SlashCommand, SlashCommandContext } from 'necord';

@Injectable()
export class DynamicCommand {
@SlashCommand({
name: 'dynamic',
description: 'This is a dynamic command'
})
async run(@Ctx() [i]: SlashCommandContext) {
return i.reply({ ephemeral: true, content: 'I am so dynamic !! 😎' });
}
}
9 changes: 9 additions & 0 deletions 09-dynamic-guilds/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
await app.init();
}

bootstrap();
10 changes: 10 additions & 0 deletions 09-dynamic-guilds/src/simple.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Injectable } from '@nestjs/common';
import { Ctx, SlashCommand, SlashCommandContext } from 'necord';

@Injectable()
export class SimpleCommand {
@SlashCommand({ name: 'ping', description: 'Bot status' })
async run(@Ctx() [i]: SlashCommandContext) {
return i.reply({ ephemeral: true, content: 'Pong !' });
}
}
5 changes: 5 additions & 0 deletions 09-dynamic-guilds/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "dist", "test", "**/*spec.ts"]
}

18 changes: 18 additions & 0 deletions 09-dynamic-guilds/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "ES2021",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}