create-discord-app 4.0.0 → 5.0.0-dev.1759924903-0c2975e3f

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/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  <br />
7
7
  <p>
8
8
  <a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
9
- <a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
9
+ <a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/tests.yml/badge.svg" alt="Build status" /></a>
10
10
  <a href="https://github.com/discordjs/discord.js/commits/main/packages/create-discord-bot"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fcreate-discord-bot" /></a>
11
11
  </p>
12
12
  <p>
@@ -23,7 +23,7 @@ It's easy to create a simple Discord bot to begin your journey with the Discord
23
23
  npm create discord-app ./your/chosen/directory
24
24
  yarn create discord-app ./your/chosen/directory
25
25
  pnpm create discord-app ./your/chosen/directory
26
- bunx create-discord-bot ./your/chosen/directory
26
+ bun create discord-app ./your/chosen/directory
27
27
  ```
28
28
 
29
29
  ## Links
@@ -31,7 +31,7 @@ bunx create-discord-bot ./your/chosen/directory
31
31
  - [Guide] ([source][guide-source])
32
32
  - Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.
33
33
  - [discord.js Discord server][discord]
34
- - [Discord API Discord server][discord-api]
34
+ - [Discord Developers Discord server][discord-developers]
35
35
  - [GitHub][source]
36
36
 
37
37
  ## Contributing
@@ -47,6 +47,6 @@ If you don't understand something in the documentation, you are experiencing pro
47
47
  [guide-source]: https://github.com/discordjs/guide
48
48
  [guide-update]: https://discordjs.guide/additional-info/changes-in-v14.html
49
49
  [discord]: https://discord.gg/djs
50
- [discord-api]: https://discord.gg/discord-api
50
+ [discord-developers]: https://discord.gg/discord-developers
51
51
  [source]: https://github.com/discordjs/discord.js/tree/main/packages/create-discord-bot
52
52
  [contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- var __defProp=Object.defineProperty,__name=(target,value)=>__defProp(target,"name",{value:value,configurable:!0});import process3 from"process";import{Option,program}from"commander";import picocolors3 from"picocolors";import prompts from"prompts";import validateProjectName from"validate-npm-package-name";var package_default_name="create-discord-app",package_default_version="4.0.0";import{cp,stat,mkdir,readdir,readFile,writeFile}from"fs/promises";import path from"path";import process2 from"process";import{URL}from"url";import glob from"fast-glob";import picocolors2 from"picocolors";import{execSync}from"child_process";import process from"process";import picocolors from"picocolors";var NODE_PACKAGE_MANAGERS=["npm","pnpm","yarn"];function resolvePackageManager(){const npmConfigUserAgent=process.env.npm_config_user_agent;return npmConfigUserAgent?npmConfigUserAgent.startsWith("npm")?"npm":npmConfigUserAgent.startsWith("yarn")?"yarn":npmConfigUserAgent.startsWith("pnpm")?"pnpm":npmConfigUserAgent.startsWith("bun")?"bun":(console.error(picocolors.yellow(`Detected an unsupported package manager (${npmConfigUserAgent}). Falling back to npm.`)),"npm"):"npm"}function install(packageManager2){let installCommand=`${packageManager2} install`;switch(console.log(`Installing dependencies with ${packageManager2}...`),packageManager2){case"yarn":console.log(),installCommand=[`${packageManager2} set version stable`,`${packageManager2} config set nodeLinker node-modules`,`${packageManager2} config set logFilters --json '[{ "code": "YN0002", "level": "discard" }, { "code": "YN0013", "level": "discard" }, { "code": "YN0032", "level": "discard" }, { "code": "YN0060", "level": "discard" }]'`,`${packageManager2} plugin import interactive-tools`,`${packageManager2} plugin import workspace-tools`,installCommand];break;case"deno":installCommand=`${packageManager2} cache --reload src/index.ts`;break;case"pnpm":case"bun":console.log()}const env={...process.env,ADBLOCK:"1",NODE_ENV:"development",DISABLE_OPENCOLLECTIVE:"1"};if(Array.isArray(installCommand))for(const[index,command]of installCommand.entries()){if(index===installCommand.length-1){execSync(command,{stdio:"inherit",env:env});break}execSync(command,{stdio:"ignore",env:env})}else execSync(installCommand,{stdio:"inherit",env:env})}function isNodePackageManager(packageManager2){return NODE_PACKAGE_MANAGERS.includes(packageManager2)}async function createDiscordBot({directory:directory,installPackages:installPackages2,typescript:typescript2,packageManager:packageManager2}){const root=path.resolve(directory),directoryName=path.basename(root);console.log();(!(await stat(root).catch((async error=>{if("ENOENT"===error.code)return await mkdir(root,{recursive:!0}),stat(root);throw error}))).isDirectory()||(await readdir(root)).length>0)&&(console.error(picocolors2.red(`The directory ${picocolors2.yellow(`"${directoryName}"`)} is either not a directory or is not empty.`)),console.error(picocolors2.red("Please specify an empty directory.")),process2.exit(1)),console.log(`Creating ${directoryName} in ${picocolors2.green(root)}.`);const deno2="deno"===packageManager2;await cp(new URL("../template/"+(deno2?"Deno":typescript2?"TypeScript":"JavaScript"),import.meta.url),root,{recursive:!0});const bun="bun"===packageManager2;bun&&(await cp(new URL(`../template/Bun/${typescript2?"TypeScript":"JavaScript"}/package.json`,import.meta.url),`${root}/package.json`),typescript2&&(await cp(new URL("../template/Bun/TypeScript/tsconfig.eslint.json",import.meta.url),`${root}/tsconfig.eslint.json`),await cp(new URL("../template/Bun/TypeScript/tsconfig.json",import.meta.url),`${root}/tsconfig.json`))),process2.chdir(root);const newVSCodeSettings=await readFile("./.vscode/settings.json",{encoding:"utf8"}).then((str=>{let newStr=str.replace("[REPLACE_ME]",deno2||bun?"auto":packageManager2);return deno2&&(newStr=newStr.replaceAll('"[REPLACE_BOOL]"',!0)),newStr}));await writeFile("./.vscode/settings.json",newVSCodeSettings);const globStream=glob.stream("./src/**/*.ts");for await(const file of globStream){const newData=await readFile(file,{encoding:"utf8"}).then((str=>str.replaceAll("[REPLACE_IMPORT_EXT]",typescript2&&!isNodePackageManager(packageManager2)?"ts":"js")));await writeFile(file,newData)}if(!deno2){const newPackageJSON=await readFile("./package.json",{encoding:"utf8"}).then((str=>{let newStr=str.replace("[REPLACE_ME]",directoryName);return newStr=newStr.replaceAll("[REPLACE_IMPORT_EXT]",typescript2&&!isNodePackageManager(packageManager2)?"ts":"js"),newStr}));await writeFile("./package.json",newPackageJSON)}if(installPackages2)try{install(packageManager2)}catch(error){console.log();"SIGINT"===error.signal?console.log(picocolors2.red("Installation aborted.")):(console.error(picocolors2.red("Installation failed.")),process2.exit(1))}console.log(),console.log(picocolors2.green("All done! Be sure to read through the discord.js guide for help on your journey.")),console.log(`Link: ${picocolors2.cyan("https://discordjs.guide")}`)}__name(resolvePackageManager,"resolvePackageManager"),__name(install,"install"),__name(isNodePackageManager,"isNodePackageManager"),__name(createDiscordBot,"createDiscordBot");var projectDirectory="",handleSigTerm=__name((()=>process3.exit(0)),"handleSigTerm");process3.on("SIGINT",handleSigTerm),process3.on("SIGTERM",handleSigTerm);var onPromptState=__name((state=>{state.aborted&&(process3.stdout.write("[?25h"),process3.stdout.write("\n"),process3.exit(1))}),"onPromptState");program.name(package_default_name).version(package_default_version).description("Create a basic discord.js bot.").argument("[directory]","What is the name of the directory you want to create this project in?").usage(`${picocolors3.green("<directory>")}`).action((directory=>{projectDirectory=directory})).option("--typescript","Whether to use the TypeScript template.").option("--javascript","Whether to use the JavaScript template.").option("--no-install","Whether to not automatically install the packages.").addOption(new Option("--package-manager <packageManager>","The package manager to use.").choices(["npm","pnpm","yarn","bun","deno"]).default(resolvePackageManager())).allowUnknownOption().parse();var{typescript:typescript,javascript:javascript,packageManager:packageManager,install:installPackages}=program.opts();if(projectDirectory||(projectDirectory=(await prompts({onState:onPromptState,type:"text",name:"directory",initial:"my-bot",message:"What is the name of the directory you want to create this project in?",validate:__name((directory=>{const validationResult=validateProjectName(directory);if(!validationResult.validForNewPackages){const errors=[];for(const error of[...validationResult.errors??[],...validationResult.warnings??[]])errors.push(picocolors3.red(`- ${error}`));return picocolors3.red(`Cannot create a project named ${picocolors3.yellow(`"${directory}"`)} due to npm naming restrictions.\n\nErrors:\n${errors.join("\n")}\n\n${picocolors3.red("\nSee https://docs.npmjs.com/cli/configuring-npm/package-json for more details.")}}`)}return!0}),"validate")})).directory),!("deno"===packageManager)&&void 0===typescript&&void 0===javascript){const{useTypescript:useTypescript}=await prompts({onState:onPromptState,type:"toggle",name:"useTypescript",message:"Do you want to use TypeScript?",initial:!0,active:"Yes",inactive:"No"});typescript=useTypescript}await createDiscordBot({typescript:typescript,directory:projectDirectory,packageManager:packageManager,installPackages:installPackages});
2
+ var __defProp=Object.defineProperty,__name=(target,value)=>__defProp(target,"name",{value:value,configurable:!0});import process3 from"process";import{styleText as styleText3}from"util";import{Option,program}from"commander";import prompts from"prompts";import validateProjectName from"validate-npm-package-name";var package_default_name="create-discord-app",package_default_version="5.0.0-dev.1759924903-0c2975e3f";import{cp,glob,mkdir,stat,readdir,readFile,writeFile}from"fs/promises";import path from"path";import process2 from"process";import{URL}from"url";import{styleText as styleText2}from"util";import{execSync}from"child_process";import process from"process";import{styleText}from"util";var NODE_PACKAGE_MANAGERS=["npm","pnpm","yarn"];function resolvePackageManager(){const npmConfigUserAgent=process.env.npm_config_user_agent;return"undefined"!=typeof Deno?"deno":npmConfigUserAgent?npmConfigUserAgent.startsWith("npm")?"npm":npmConfigUserAgent.startsWith("yarn")?"yarn":npmConfigUserAgent.startsWith("pnpm")?"pnpm":npmConfigUserAgent.startsWith("bun")?"bun":(console.error(styleText("yellow",`Detected an unsupported package manager (${npmConfigUserAgent}). Falling back to npm.`)),"npm"):"npm"}function install(packageManager2){let installCommand=`${packageManager2} install`;switch(console.log(`Installing dependencies with ${packageManager2}...`),packageManager2){case"yarn":console.log(),installCommand=[`${packageManager2} set version stable`,`${packageManager2} config set nodeLinker node-modules`,`${packageManager2} config set logFilters --json '[{ "code": "YN0002", "level": "discard" }, { "code": "YN0013", "level": "discard" }, { "code": "YN0032", "level": "discard" }, { "code": "YN0060", "level": "discard" }]'`,`${packageManager2} plugin import interactive-tools`,`${packageManager2} plugin import workspace-tools`,installCommand];break;case"deno":installCommand=`${packageManager2} cache --reload src/index.ts`;break;case"pnpm":case"bun":console.log()}const env={...process.env,ADBLOCK:"1",NODE_ENV:"development",DISABLE_OPENCOLLECTIVE:"1"};if(Array.isArray(installCommand))for(const[index,command]of installCommand.entries()){if(index===installCommand.length-1){execSync(command,{stdio:"inherit",env:env});break}execSync(command,{stdio:"ignore",env:env})}else execSync(installCommand,{stdio:"inherit",env:env})}function isNodePackageManager(packageManager2){return NODE_PACKAGE_MANAGERS.includes(packageManager2)}async function createDiscordBot({directory:directory,installPackages:installPackages2,typescript:typescript2,packageManager:packageManager2}){const root=path.resolve(directory),directoryName=path.basename(root);console.log();(!(await stat(root).catch(async error=>{if("ENOENT"===error.code)return await mkdir(root,{recursive:!0}),stat(root);throw error})).isDirectory()||(await readdir(root)).length>0)&&(console.error(styleText2("red",`The directory ${styleText2("yellow",`"${directoryName}"`)} is either not a directory or is not empty.`)),console.error(styleText2("red","Please specify an empty directory.")),process2.exit(1)),console.log(`Creating ${directoryName} in ${styleText2("green",root)}.`);const deno2="deno"===packageManager2;await cp(new URL("../template/"+(deno2?"Deno":typescript2?"TypeScript":"JavaScript"),import.meta.url),root,{recursive:!0});const bun="bun"===packageManager2;bun&&(await cp(new URL(`../template/Bun/${typescript2?"TypeScript":"JavaScript"}/package.json`,import.meta.url),`${root}/package.json`),typescript2&&(await cp(new URL("../template/Bun/TypeScript/tsconfig.eslint.json",import.meta.url),`${root}/tsconfig.eslint.json`),await cp(new URL("../template/Bun/TypeScript/tsconfig.json",import.meta.url),`${root}/tsconfig.json`))),process2.chdir(root);const newVSCodeSettings=await readFile("./.vscode/settings.json",{encoding:"utf8"}).then(str=>{let newStr=str.replace("[REPLACE_ME]",deno2||bun?"auto":packageManager2);return deno2&&(newStr=newStr.replaceAll('"[REPLACE_BOOL]"',!0)),newStr});await writeFile("./.vscode/settings.json",newVSCodeSettings);const globIterator=glob("./src/**/*.ts");for await(const file of globIterator){const newData=await readFile(file,{encoding:"utf8"}).then(str=>str.replaceAll("[REPLACE_IMPORT_EXT]",typescript2&&!isNodePackageManager(packageManager2)?"ts":"js"));await writeFile(file,newData)}if(!deno2){const newPackageJSON=await readFile("./package.json",{encoding:"utf8"}).then(str=>{let newStr=str.replace("[REPLACE_ME]",directoryName);return newStr=newStr.replaceAll("[REPLACE_IMPORT_EXT]",typescript2&&!isNodePackageManager(packageManager2)?"ts":"js"),newStr});await writeFile("./package.json",newPackageJSON)}if(installPackages2)try{install(packageManager2)}catch(error){console.log();"SIGINT"===error.signal?console.log(styleText2("red","Installation aborted.")):(console.error(styleText2("red","Installation failed.")),process2.exit(1))}console.log(),console.log(styleText2("green","All done! Be sure to read through the discord.js guide for help on your journey.")),console.log(`Link: ${styleText2("cyan","https://discordjs.guide")}`)}__name(resolvePackageManager,"resolvePackageManager"),__name(install,"install"),__name(isNodePackageManager,"isNodePackageManager"),__name(createDiscordBot,"createDiscordBot");var projectDirectory="",handleSigTerm=__name(()=>process3.exit(0),"handleSigTerm");process3.on("SIGINT",handleSigTerm),process3.on("SIGTERM",handleSigTerm);var onPromptState=__name(state=>{state.aborted&&(process3.stdout.write("[?25h"),process3.stdout.write("\n"),process3.exit(1))},"onPromptState");program.name(package_default_name).version(package_default_version).description("Create a basic discord.js bot.").argument("[directory]","What is the name of the directory you want to create this project in?").usage(`${styleText3("green","<directory>")}`).action(directory=>{projectDirectory=directory}).option("--typescript","Whether to use the TypeScript template.").option("--javascript","Whether to use the JavaScript template.").option("--no-install","Whether to not automatically install the packages.").addOption(new Option("--package-manager <packageManager>","The package manager to use.").choices(["npm","pnpm","yarn","bun","deno"]).default(resolvePackageManager())).allowUnknownOption().parse();var{typescript:typescript,javascript:javascript,packageManager:packageManager,install:installPackages}=program.opts();if(projectDirectory||(projectDirectory=(await prompts({onState:onPromptState,type:"text",name:"directory",initial:"my-bot",message:"What is the name of the directory you want to create this project in?",validate:__name(directory=>{const validationResult=validateProjectName(directory);if(!validationResult.validForNewPackages){const errors=[];for(const error of[...validationResult.errors??[],...validationResult.warnings??[]])errors.push(styleText3("red",`- ${error}`));return styleText3("red",`Cannot create a project named ${styleText3("yellow",`"${directory}"`)} due to npm naming restrictions.\n\nErrors:\n${errors.join("\n")}\n\n${styleText3("red","\nSee https://docs.npmjs.com/cli/configuring-npm/package-json for more details.")}}`)}return!0},"validate")})).directory),!("deno"===packageManager)&&void 0===typescript&&void 0===javascript){const{useTypescript:useTypescript}=await prompts({onState:onPromptState,type:"toggle",name:"useTypescript",message:"Do you want to use TypeScript?",initial:!0,active:"Yes",inactive:"No"});typescript=useTypescript}await createDiscordBot({typescript:typescript,directory:projectDirectory,packageManager:packageManager,installPackages:installPackages});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "create-discord-app",
4
- "version": "4.0.0",
4
+ "version": "5.0.0-dev.1759924903-0c2975e3f",
5
5
  "description": "A simple way to create a startup Discord bot.",
6
6
  "type": "module",
7
7
  "bin": "./dist/index.js",
@@ -41,33 +41,32 @@
41
41
  "homepage": "https://discord.js.org",
42
42
  "funding": "https://github.com/discordjs/discord.js?sponsor",
43
43
  "dependencies": {
44
- "commander": "^13.1.0",
45
- "fast-glob": "^3.3.3",
46
- "picocolors": "^1.1.1",
44
+ "commander": "^14.0.1",
47
45
  "prompts": "^2.4.2",
48
- "validate-npm-package-name": "^6.0.0"
46
+ "validate-npm-package-name": "^6.0.2"
49
47
  },
50
48
  "devDependencies": {
51
49
  "@favware/cliff-jumper": "^4.1.0",
52
- "@types/node": "^22.15.2",
50
+ "@types/node": "^22.18.8",
53
51
  "@types/prompts": "^2.4.9",
54
52
  "@types/validate-npm-package-name": "^4.0.2",
55
- "cross-env": "^7.0.3",
56
- "eslint": "^9.25.1",
53
+ "cross-env": "^10.1.0",
54
+ "eslint": "^9.37.0",
57
55
  "eslint-config-neon": "^0.2.7",
58
56
  "eslint-formatter-compact": "^8.40.0",
59
- "eslint-formatter-pretty": "^6.0.1",
60
- "prettier": "^3.5.3",
61
- "terser": "^5.39.0",
62
- "tsup": "^8.4.0",
63
- "typescript": "~5.8.3",
57
+ "eslint-formatter-pretty": "^7.0.0",
58
+ "prettier": "^3.6.2",
59
+ "terser": "^5.44.0",
60
+ "tsup": "^8.5.0",
61
+ "typescript": "~5.9.3",
64
62
  "@discordjs/api-extractor": "^7.52.7"
65
63
  },
66
64
  "engines": {
67
65
  "node": ">=22.12.0"
68
66
  },
69
67
  "publishConfig": {
70
- "access": "public"
68
+ "access": "public",
69
+ "provenance": true
71
70
  },
72
71
  "scripts": {
73
72
  "build": "tsc --noEmit && tsup",
@@ -11,15 +11,15 @@
11
11
  "start": "bun run src/index.[REPLACE_IMPORT_EXT]"
12
12
  },
13
13
  "dependencies": {
14
- "@discordjs/core": "^2.1.1",
15
- "discord.js": "^14.20.0"
14
+ "@discordjs/core": "^2.2.2",
15
+ "discord.js": "^14.22.1"
16
16
  },
17
17
  "devDependencies": {
18
- "eslint": "^9.24.0",
18
+ "eslint": "^9.37.0",
19
19
  "eslint-config-neon": "^0.2.7",
20
20
  "eslint-formatter-compact": "^8.40.0",
21
- "eslint-formatter-pretty": "^6.0.1",
22
- "prettier": "^3.5.3",
23
- "zod": "^3.24.1"
21
+ "eslint-formatter-pretty": "^7.0.0",
22
+ "prettier": "^3.6.2",
23
+ "zod": "^3.25.76"
24
24
  }
25
25
  }
@@ -11,18 +11,18 @@
11
11
  "start": "bun run src/index.[REPLACE_IMPORT_EXT]"
12
12
  },
13
13
  "dependencies": {
14
- "@discordjs/core": "^2.1.1",
15
- "discord.js": "^14.20.0"
14
+ "@discordjs/core": "^2.2.2",
15
+ "discord.js": "^14.22.1"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@sapphire/ts-config": "^5.0.1",
19
- "@types/bun": "^1.1.14",
20
- "eslint": "^9.24.0",
19
+ "@types/bun": "^1.2.23",
20
+ "eslint": "^9.37.0",
21
21
  "eslint-config-neon": "^0.2.7",
22
22
  "eslint-formatter-compact": "^8.40.0",
23
- "eslint-formatter-pretty": "^6.0.1",
24
- "prettier": "^3.5.3",
25
- "typescript": "~5.5.4",
26
- "zod": "^3.24.1"
23
+ "eslint-formatter-pretty": "^7.0.0",
24
+ "prettier": "^3.6.2",
25
+ "typescript": "~5.9.3",
26
+ "zod": "^3.25.76"
27
27
  }
28
28
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "recommendations": ["denoland.vscode-deno", "tamasfe.even-better-toml", "codezombiech.gitignore"]
2
+ "recommendations": ["denoland.vscode-deno"]
3
3
  }
@@ -2,14 +2,11 @@
2
2
  "editor.defaultFormatter": "denoland.vscode-deno",
3
3
  "editor.formatOnSave": true,
4
4
  "editor.codeActionsOnSave": {
5
- "source.fixAll": true,
6
- "source.organizeImports": false
5
+ "source.fixAll": "always",
6
+ "source.organizeImports": "always"
7
7
  },
8
8
  "editor.trimAutoWhitespace": false,
9
9
  "files.insertFinalNewline": true,
10
10
  "files.eol": "\n",
11
- "npm.packageManager": "[REPLACE_ME]",
12
- "deno.enable": "[REPLACE_BOOL]",
13
- "deno.lint": "[REPLACE_BOOL]",
14
- "deno.unstable": false
11
+ "deno.enable": "[REPLACE_BOOL]"
15
12
  }
@@ -2,40 +2,25 @@
2
2
  "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json",
3
3
  "tasks": {
4
4
  "lint": "deno lint",
5
- "deploy": "deno run --allow-read --allow-env --allow-net src/util/deploy.ts",
5
+ "deploy": "deno run --env-file --allow-read --allow-env --allow-net src/util/deploy.ts",
6
6
  "format": "deno fmt",
7
7
  "fmt": "deno fmt",
8
- "start": "deno run --allow-read --allow-env --allow-net src/index.ts",
8
+ "start": "deno run --env-file --allow-read --allow-env --allow-net src/index.ts",
9
+ },
10
+ "fmt": {
11
+ "useTabs": true,
12
+ "lineWidth": 120,
13
+ "singleQuote": true,
9
14
  },
10
15
  "lint": {
11
- "include": ["src/"],
12
16
  "rules": {
13
17
  "tags": ["recommended"],
14
18
  "exclude": ["require-await", "no-await-in-sync-fn"],
15
19
  },
16
20
  },
17
- "fmt": {
18
- "useTabs": true,
19
- "lineWidth": 120,
20
- "semiColons": true,
21
- "singleQuote": true,
22
- "proseWrap": "preserve",
23
- "include": ["src/"],
24
- },
25
- "compilerOptions": {
26
- "alwaysStrict": true,
27
- "emitDecoratorMetadata": true,
28
- "verbatimModuleSyntax": true,
29
- "lib": ["deno.window"],
30
- "noFallthroughCasesInSwitch": true,
31
- "noImplicitReturns": true,
32
- "noUnusedLocals": true,
33
- "noUnusedParameters": true,
34
- "removeComments": false,
35
- "strict": true,
36
- "allowUnreachableCode": false,
37
- "allowUnusedLabels": false,
38
- "exactOptionalPropertyTypes": false,
39
- "noImplicitOverride": true,
21
+ "imports": {
22
+ "@discordjs/core": "npm:@discordjs/core@^2.2.2",
23
+ "discord.js": "npm:discord.js@^14.22.1",
24
+ "zod": "npm:zod@^3.25.76",
40
25
  },
41
26
  }
@@ -1,5 +1,5 @@
1
- import type { RESTPostAPIApplicationCommandsJSONBody, CommandInteraction } from 'npm:discord.js@^14.20.0';
2
- import { z } from 'npm:zod@^3.24.1';
1
+ import type { CommandInteraction, RESTPostAPIApplicationCommandsJSONBody } from 'discord.js';
2
+ import { z } from 'zod';
3
3
  import type { StructurePredicate } from '../util/loaders.ts';
4
4
 
5
5
  /**
@@ -1,21 +1,21 @@
1
- import type { ClientEvents } from 'npm:discord.js@^14.20.0';
2
- import { z } from 'npm:zod@^3.24.1';
1
+ import type { ClientEvents } from 'discord.js';
2
+ import { z } from 'zod';
3
3
  import type { StructurePredicate } from '../util/loaders.ts';
4
4
 
5
5
  /**
6
6
  * Defines the structure of an event.
7
7
  */
8
- export type Event<T extends keyof ClientEvents = keyof ClientEvents> = {
8
+ export type Event<EventName extends keyof ClientEvents = keyof ClientEvents> = {
9
9
  /**
10
10
  * The function to execute when the event is emitted.
11
11
  *
12
12
  * @param parameters - The parameters of the event
13
13
  */
14
- execute(...parameters: ClientEvents[T]): Promise<void> | void;
14
+ execute(...parameters: ClientEvents[EventName]): Promise<void> | void;
15
15
  /**
16
16
  * The name of the event to listen to
17
17
  */
18
- name: T;
18
+ name: EventName;
19
19
  /**
20
20
  * Whether or not the event should only be listened to once
21
21
  *
@@ -1,4 +1,4 @@
1
- import { Events } from 'npm:discord.js@^14.20.0';
1
+ import { Events } from 'discord.js';
2
2
  import type { Event } from './index.ts';
3
3
  import { loadCommands } from '../util/loaders.ts';
4
4
 
@@ -1,4 +1,4 @@
1
- import { Events } from 'npm:discord.js@^14.20.0';
1
+ import { Events } from 'discord.js';
2
2
  import type { Event } from './index.ts';
3
3
 
4
4
  export default {
@@ -1,6 +1,4 @@
1
- import 'https://deno.land/std@0.223.0/dotenv/load.ts';
2
- import { URL } from 'node:url';
3
- import { Client, GatewayIntentBits } from 'npm:discord.js@^14.20.0';
1
+ import { Client, GatewayIntentBits } from 'discord.js';
4
2
  import { loadEvents } from './util/loaders.ts';
5
3
 
6
4
  // Initialize the client
@@ -1,7 +1,5 @@
1
- import 'https://deno.land/std@0.223.0/dotenv/load.ts';
2
- import { URL } from 'node:url';
3
- import { API } from 'npm:@discordjs/core@^2.1.1/http-only';
4
- import { REST } from 'npm:discord.js@^14.20.0';
1
+ import { API } from '@discordjs/core/http-only';
2
+ import { REST } from 'discord.js';
5
3
  import { loadCommands } from './loaders.ts';
6
4
 
7
5
  const commands = await loadCommands(new URL('../commands/', import.meta.url));
@@ -1,6 +1,7 @@
1
1
  import type { PathLike } from 'node:fs';
2
- import { readdir, stat } from 'node:fs/promises';
3
- import { URL } from 'node:url';
2
+ import { glob, stat } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
4
5
  import type { Command } from '../commands/index.ts';
5
6
  import { predicate as commandPredicate } from '../commands/index.ts';
6
7
  import type { Event } from '../events/index.ts';
@@ -9,7 +10,7 @@ import { predicate as eventPredicate } from '../events/index.ts';
9
10
  /**
10
11
  * A predicate to check if the structure is valid
11
12
  */
12
- export type StructurePredicate<T> = (structure: unknown) => structure is T;
13
+ export type StructurePredicate<Structure> = (structure: unknown) => structure is Structure;
13
14
 
14
15
  /**
15
16
  * Loads all the structures in the provided directory
@@ -19,11 +20,11 @@ export type StructurePredicate<T> = (structure: unknown) => structure is T;
19
20
  * @param recursive - Whether to recursively load the structures in the directory
20
21
  * @returns
21
22
  */
22
- export async function loadStructures<T>(
23
+ export async function loadStructures<Structure>(
23
24
  dir: PathLike,
24
- predicate: StructurePredicate<T>,
25
+ predicate: StructurePredicate<Structure>,
25
26
  recursive = true,
26
- ): Promise<T[]> {
27
+ ): Promise<Structure[]> {
27
28
  // Get the stats of the directory
28
29
  const statDir = await stat(dir);
29
30
 
@@ -32,34 +33,24 @@ export async function loadStructures<T>(
32
33
  throw new Error(`The directory '${dir}' is not a directory.`);
33
34
  }
34
35
 
35
- // Get all the files in the directory
36
- const files = await readdir(dir);
37
-
38
36
  // Create an empty array to store the structures
39
- const structures: T[] = [];
40
-
41
- // Loop through all the files in the directory
42
- for (const file of files) {
43
- const fileUrl = new URL(`${dir}/${file}`, import.meta.url);
44
-
45
- // Get the stats of the file
46
- const statFile = await stat(fileUrl);
37
+ const structures: Structure[] = [];
47
38
 
48
- // If the file is a directory and recursive is true, recursively load the structures in the directory
49
- if (statFile.isDirectory() && recursive) {
50
- structures.push(...(await loadStructures(fileUrl, predicate, recursive)));
51
- continue;
52
- }
39
+ // Create a glob pattern to match the .ts files
40
+ const basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();
41
+ const pattern = resolve(basePath, recursive ? '**/*.ts' : '*.ts');
53
42
 
54
- // If the file is index.ts or the file does not end with .ts, skip the file
55
- if (file === 'index.ts' || !file.endsWith('.ts')) {
43
+ // Loop through all the matching files in the directory
44
+ for await (const file of glob(pattern)) {
45
+ // If the file is index.ts, skip the file
46
+ if (file.endsWith('/index.ts')) {
56
47
  continue;
57
48
  }
58
49
 
59
50
  // Import the structure dynamically from the file
60
- const structure = (await import(fileUrl.toString())).default;
51
+ const { default: structure } = await import(file);
61
52
 
62
- // If the structure is a valid structure, add it
53
+ // If the default export is a valid structure, add it
63
54
  if (predicate(structure)) {
64
55
  structures.push(structure);
65
56
  }
@@ -7,21 +7,20 @@
7
7
  "scripts": {
8
8
  "lint": "prettier --check . && eslint --ext .js,.mjs,.cjs --format=pretty src",
9
9
  "format": "prettier --write . && eslint --ext .js,.mjs,.cjs --fix --format=pretty src",
10
- "start": "node --require dotenv/config src/index.js",
11
- "deploy": "node --require dotenv/config src/util/deploy.js"
10
+ "start": "node --env-file=.env src/index.js",
11
+ "deploy": "node --env-file=.env src/util/deploy.js"
12
12
  },
13
13
  "dependencies": {
14
- "@discordjs/core": "^2.1.1",
15
- "discord.js": "^14.20.0",
16
- "dotenv": "^16.4.5"
14
+ "@discordjs/core": "^2.2.2",
15
+ "discord.js": "^14.22.1"
17
16
  },
18
17
  "devDependencies": {
19
- "eslint": "^9.24.0",
18
+ "eslint": "^9.37.0",
20
19
  "eslint-config-neon": "^0.2.7",
21
20
  "eslint-formatter-compact": "^8.40.0",
22
- "eslint-formatter-pretty": "^6.0.1",
23
- "prettier": "^3.5.3",
24
- "zod": "^3.24.1"
21
+ "eslint-formatter-pretty": "^7.0.0",
22
+ "prettier": "^3.6.2",
23
+ "zod": "^3.25.76"
25
24
  },
26
25
  "engines": {
27
26
  "node": ">=22.12.0"
@@ -3,10 +3,10 @@ import { z } from 'zod';
3
3
  /**
4
4
  * Defines the structure of an event.
5
5
  *
6
- * @template {keyof import('discord.js').ClientEvents} [T=keyof import('discord.js').ClientEvents]
6
+ * @template {keyof import('discord.js').ClientEvents} [EventName=keyof import('discord.js').ClientEvents]
7
7
  * @typedef {object} Event
8
- * @property {(...parameters: import('discord.js').ClientEvents[T]) => Promise<void> | void} execute The function to execute the command
9
- * @property {T} name The name of the event to listen to
8
+ * @property {(...parameters: import('discord.js').ClientEvents[EventName]) => Promise<void> | void} execute The function to execute the command
9
+ * @property {EventName} name The name of the event to listen to
10
10
  * @property {boolean} [once] Whether or not the event should only be listened to once
11
11
  */
12
12
 
@@ -1,23 +1,23 @@
1
- import { readdir, stat } from 'node:fs/promises';
2
- import { URL } from 'node:url';
1
+ import { glob, stat } from 'node:fs/promises';
2
+ import { fileURLToPath, resolve, URL } from 'node:url';
3
3
  import { predicate as commandPredicate } from '../commands/index.js';
4
4
  import { predicate as eventPredicate } from '../events/index.js';
5
5
 
6
6
  /**
7
7
  * A predicate to check if the structure is valid.
8
8
  *
9
- * @template T
10
- * @typedef {(structure: unknown) => structure is T} StructurePredicate
9
+ * @template Structure
10
+ * @typedef {(structure: unknown) => structure is Structure} StructurePredicate
11
11
  */
12
12
 
13
13
  /**
14
14
  * Loads all the structures in the provided directory.
15
15
  *
16
- * @template T
16
+ * @template Structure
17
17
  * @param {import('node:fs').PathLike} dir - The directory to load the structures from
18
- * @param {StructurePredicate<T>} predicate - The predicate to check if the structure is valid
18
+ * @param {StructurePredicate<Structure>} predicate - The predicate to check if the structure is valid
19
19
  * @param {boolean} recursive - Whether to recursively load the structures in the directory
20
- * @returns {Promise<T[]>}
20
+ * @returns {Promise<Structure[]>}
21
21
  */
22
22
  export async function loadStructures(dir, predicate, recursive = true) {
23
23
  // Get the stats of the directory
@@ -28,35 +28,25 @@ export async function loadStructures(dir, predicate, recursive = true) {
28
28
  throw new Error(`The directory '${dir}' is not a directory.`);
29
29
  }
30
30
 
31
- // Get all the files in the directory
32
- const files = await readdir(dir);
33
-
34
31
  // Create an empty array to store the structures
35
- /** @type {T[]} */
32
+ /** @type {Structure[]} */
36
33
  const structures = [];
37
34
 
38
- // Loop through all the files in the directory
39
- for (const file of files) {
40
- const fileUrl = new URL(`${dir}/${file}`, import.meta.url);
41
-
42
- // Get the stats of the file
43
- const statFile = await stat(fileUrl);
44
-
45
- // If the file is a directory and recursive is true, recursively load the structures in the directory
46
- if (statFile.isDirectory() && recursive) {
47
- structures.push(...(await loadStructures(fileUrl, predicate, recursive)));
48
- continue;
49
- }
35
+ // Create a glob pattern to match the .js files
36
+ const basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();
37
+ const pattern = resolve(basePath, recursive ? '**/*.js' : '*.js');
50
38
 
51
- // If the file is index.js or the file does not end with .js, skip the file
52
- if (file === 'index.js' || !file.endsWith('.js')) {
39
+ // Loop through all the matching files in the directory
40
+ for await (const file of glob(pattern)) {
41
+ // If the file is index.js, skip the file
42
+ if (file.endsWith('/index.js')) {
53
43
  continue;
54
44
  }
55
45
 
56
46
  // Import the structure dynamically from the file
57
- const structure = (await import(fileUrl.toString())).default;
47
+ const { default: structure } = await import(file);
58
48
 
59
- // If the structure is a valid structure, add it
49
+ // If the default export is a valid structure, add it
60
50
  if (predicate(structure)) {
61
51
  structures.push(structure);
62
52
  }
@@ -68,7 +58,7 @@ export async function loadStructures(dir, predicate, recursive = true) {
68
58
  /**
69
59
  * @param {import('node:fs').PathLike} dir
70
60
  * @param {boolean} [recursive]
71
- * @returns {Promise<Map<string,import('../commands/index.js').Command>>}
61
+ * @returns {Promise<Map<string, import('../commands/index.js').Command>>}
72
62
  */
73
63
  export async function loadCommands(dir, recursive = true) {
74
64
  return (await loadStructures(dir, commandPredicate, recursive)).reduce(
@@ -3,8 +3,8 @@
3
3
  "editor.defaultFormatter": "esbenp.prettier-vscode",
4
4
  "editor.formatOnSave": true,
5
5
  "editor.codeActionsOnSave": {
6
- "source.fixAll": true,
7
- "source.organizeImports": false
6
+ "source.fixAll": "explicit",
7
+ "source.organizeImports": "never"
8
8
  },
9
9
  "editor.trimAutoWhitespace": false,
10
10
  "files.insertFinalNewline": true,
@@ -7,25 +7,24 @@
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "lint": "prettier --check . && eslint --ext .ts --format=pretty src",
10
- "deploy": "node --require dotenv/config dist/util/deploy.js",
10
+ "deploy": "node --env-file=.env dist/util/deploy.js",
11
11
  "format": "prettier --write . && eslint --ext .ts --fix --format=pretty src",
12
- "start": "node --require dotenv/config dist/index.js"
12
+ "start": "node --env-file=.env dist/index.js"
13
13
  },
14
14
  "dependencies": {
15
- "@discordjs/core": "^2.1.1",
16
- "discord.js": "^14.20.0",
17
- "dotenv": "^16.4.7"
15
+ "@discordjs/core": "^2.2.2",
16
+ "discord.js": "^14.22.1"
18
17
  },
19
18
  "devDependencies": {
20
19
  "@sapphire/ts-config": "^5.0.1",
21
- "@types/node": "^22.10.10",
22
- "eslint": "^9.24.0",
20
+ "@types/node": "^22.18.8",
21
+ "eslint": "^9.37.0",
23
22
  "eslint-config-neon": "^0.2.7",
24
23
  "eslint-formatter-compact": "^8.40.0",
25
- "eslint-formatter-pretty": "^6.0.1",
26
- "prettier": "^3.5.3",
27
- "typescript": "~5.5.4",
28
- "zod": "^3.24.1"
24
+ "eslint-formatter-pretty": "^7.0.0",
25
+ "prettier": "^3.6.2",
26
+ "typescript": "~5.9.3",
27
+ "zod": "^3.25.76"
29
28
  },
30
29
  "engines": {
31
30
  "node": ">=22.12.0"
@@ -5,17 +5,17 @@ import type { StructurePredicate } from '../util/loaders.[REPLACE_IMPORT_EXT]';
5
5
  /**
6
6
  * Defines the structure of an event.
7
7
  */
8
- export type Event<T extends keyof ClientEvents = keyof ClientEvents> = {
8
+ export type Event<EventName extends keyof ClientEvents = keyof ClientEvents> = {
9
9
  /**
10
10
  * The function to execute when the event is emitted.
11
11
  *
12
12
  * @param parameters - The parameters of the event
13
13
  */
14
- execute(...parameters: ClientEvents[T]): Promise<void> | void;
14
+ execute(...parameters: ClientEvents[EventName]): Promise<void> | void;
15
15
  /**
16
16
  * The name of the event to listen to
17
17
  */
18
- name: T;
18
+ name: EventName;
19
19
  /**
20
20
  * Whether or not the event should only be listened to once
21
21
  *
@@ -1,6 +1,7 @@
1
1
  import type { PathLike } from 'node:fs';
2
- import { readdir, stat } from 'node:fs/promises';
3
- import { URL } from 'node:url';
2
+ import { glob, stat } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
4
5
  import type { Command } from '../commands/index.[REPLACE_IMPORT_EXT]';
5
6
  import { predicate as commandPredicate } from '../commands/index.[REPLACE_IMPORT_EXT]';
6
7
  import type { Event } from '../events/index.[REPLACE_IMPORT_EXT]';
@@ -9,7 +10,7 @@ import { predicate as eventPredicate } from '../events/index.[REPLACE_IMPORT_EXT
9
10
  /**
10
11
  * A predicate to check if the structure is valid
11
12
  */
12
- export type StructurePredicate<T> = (structure: unknown) => structure is T;
13
+ export type StructurePredicate<Structure> = (structure: unknown) => structure is Structure;
13
14
 
14
15
  /**
15
16
  * Loads all the structures in the provided directory
@@ -19,11 +20,11 @@ export type StructurePredicate<T> = (structure: unknown) => structure is T;
19
20
  * @param recursive - Whether to recursively load the structures in the directory
20
21
  * @returns
21
22
  */
22
- export async function loadStructures<T>(
23
+ export async function loadStructures<Structure>(
23
24
  dir: PathLike,
24
- predicate: StructurePredicate<T>,
25
+ predicate: StructurePredicate<Structure>,
25
26
  recursive = true,
26
- ): Promise<T[]> {
27
+ ): Promise<Structure[]> {
27
28
  // Get the stats of the directory
28
29
  const statDir = await stat(dir);
29
30
 
@@ -32,35 +33,27 @@ export async function loadStructures<T>(
32
33
  throw new Error(`The directory '${dir}' is not a directory.`);
33
34
  }
34
35
 
35
- // Get all the files in the directory
36
- const files = await readdir(dir);
37
-
38
36
  // Create an empty array to store the structures
39
- const structures: T[] = [];
40
-
41
- // Loop through all the files in the directory
42
- for (const file of files) {
43
- const fileUrl = new URL(`${dir}/${file}`, import.meta.url);
44
-
45
- // Get the stats of the file
46
- const statFile = await stat(fileUrl);
37
+ const structures: Structure[] = [];
47
38
 
48
- // If the file is a directory and recursive is true, recursively load the structures in the directory
49
- if (statFile.isDirectory() && recursive) {
50
- structures.push(...(await loadStructures(fileUrl, predicate, recursive)));
51
- continue;
52
- }
39
+ // Create a glob pattern to match the .[REPLACE_IMPORT_EXT] files
40
+ const basePath = dir instanceof URL ? fileURLToPath(dir) : dir.toString();
41
+ const pattern = resolve(basePath, recursive ? '**/*.[REPLACE_IMPORT_EXT]' : '*.[REPLACE_IMPORT_EXT]');
53
42
 
54
- // If the file is index.[REPLACE_IMPORT_EXT] or the file does not end with .[REPLACE_IMPORT_EXT], skip the file
55
- if (file === 'index.[REPLACE_IMPORT_EXT]' || !file.endsWith('.[REPLACE_IMPORT_EXT]')) {
43
+ // Loop through all the matching files in the directory
44
+ for await (const file of glob(pattern)) {
45
+ // If the file is index.[REPLACE_IMPORT_EXT], skip the file
46
+ if (file.endsWith('/index.[REPLACE_IMPORT_EXT]')) {
56
47
  continue;
57
48
  }
58
49
 
59
50
  // Import the structure dynamically from the file
60
- const structure = (await import(fileUrl.toString())).default;
51
+ const { default: structure } = await import(file);
61
52
 
62
- // If the structure is a valid structure, add it
63
- if (predicate(structure)) structures.push(structure);
53
+ // If the default export is a valid structure, add it
54
+ if (predicate(structure)) {
55
+ structures.push(structure);
56
+ }
64
57
  }
65
58
 
66
59
  return structures;
@@ -1,9 +0,0 @@
1
- {
2
- "$schema": "https://json.schemastore.org/prettierrc.json",
3
- "printWidth": 120,
4
- "useTabs": true,
5
- "singleQuote": true,
6
- "quoteProps": "as-needed",
7
- "trailingComma": "all",
8
- "endOfLine": "lf"
9
- }