Files
discordeno/apps/site/docs/migrating.md
Skillz4Killz 2714e1e7d1 BREAKING: node migration + major improvements and style changes (#2783)
* Setup turborepo (#2610)

* chore: BREAKING move to monorepo structure

* chore: setup turborepo

* setup more eslint and tsconfig (#2612)

* fix packages setting lcoation

* add dist to ignore

* style

* fix: .vscode set prettier and remove deno configs (#2611)

* fix: rewrite to process.env

* chore: add node types

* style: run eslint --fix

* fix: tests import ext

* chore: fix formatter

* chore: add build script

* chore: remove site from turborepo

* chore: move to seperate packages

* chore: seperate util

* chore: rename to index

* fix: utils

* chore: bump typescript

* fix: in process of fixing rest

* fix: logger

* style

* chore: fix turbo script

* fix: types

* fix: types

* fix: shard

* fix: gateway

* fixing: bot

* fix: at least it can run now

* chore: fix turbo script

* chore: move plugins

* chore: add type and utils export

* chore: working bot type and cache plugin

* Add git hooks (#2618)

* CI: Setup ci (#2669)

* ci: fix test

* ci: fix typo

* fix: turbo script

* fixes: yarn and linter errors in embeds pkg

* chore: fix yarn gitignore

* Node migration - devcontainer (#2672)

*  - feat: devcontainer -> node

* 👷‍♂ - ci: devcontainer - add tabnine, prettier

* fix: ignore .env and debug.ts

* fix: couple of linter errors

* fix: linter error

* fix: gateway linter errors

* style: update style

* style: fix bot style

* fix: type

* ci: move all old workflow

* chore: close #2619

* chore: close #2671

* test: add mocha

* chore: add typescript plugin

* test: add mocha

* test: add test to utils

* test/ci: update ci and coverage

* chore: change script naming

* ci: update include test

* test: add coverage

* ci: fix cache

* ci: fix ci and codecov

* Discordeno Documentation  (#2673)

* Add git hooks

* Add documentation generatation

* Change Documentation Engine

* Add documentation

* Remove autogenerated docs

* combine lint staged action into one

* style: fix

Co-authored-by: H01001000 <heiheiho000@gmail.com>

* chore: new package client

* test: add rest test

* ci: enable codecov

* fix: type

* test: add test to all packages

* ci: add release to gh per commit

* fix: ci syntax

* fix: package version

* fix: publish script

* fix: remove private from gateway

* ci: add filter for changes

* fix: ci syntex

* ci: try fix path filter

* ci: try fix path filter

* test: add test

* ci: fix string and  boolean

* fix: package and ci

* chore: fix turbo type cache

* ci: also publish to npm

* ci: change to public

* fix: not publish to npm

* fix: dependencies

* chore: fix fmt script

* fix: better rest typecheck Closes #2621

* fix: run yarn install

* feat: add transformers to rest

* feat: add helpers to rest

* test: move bot utils test

* reverse change to release.yml

* chore: add clean build

* refactor: discordeno

* chore: add import type

* chore: remove bot

* fix: change deps from bot to dd

* chore: update yarn lock

* test: temp remove test from logger

* refactor: remove transformers in helpers/channel

* type: close #2622

* ci(fix): explicitly define coverage file

* refactor: remove transformers in helpers/emoji

* type: fix discord guild type

* feat: DiscordEditAutomoderationRule type

* fix: remove unused type

* feat: DiscordCreateGuildEmoji DiscordModifyGuildEmoji & DiscordModifyCHannel types

* feat: DiscordCreateChannel DiscordBuDeleteMessages DiscordCreateMessage DiscordEditMessage

* feat: DiscordCreateScheduledEvent EditScheduledEvent DiscordCreateInvite

* fix: types for guild stuff for rest

* feat: thread discord types for rest

* feat: channel rest types

* feat: member rest types

* feat: more discord rest types

* fix: type errors

* fix: docs bot param name should be rest

* type: fix type error

* ci(fix): codecov

* chore(client) :add export transformer

* fix: verifySignature

* test: fix types

* test: add test prevent #2683 #2678

* fix: export transformer twice

* ci: reuse cache

* test: add test:unit-noTextCoverage

* feat: add transform and constant package

* fix: half fix #2683 #2688

* fix: #2688 fix all transformer.spec.ts

* fix: transformer name

* ci: update style

* fix: dependencies

* fix: naming

* fix: yarn lock

* fix: remove validations from helpers. Closes #2700

* fix: rest routes as a constants pkg

* fix: esm import with .js

* test: add exception case

* feat: adding transformer

* chore: change script name

* chore: add path fixing to coverage file

* fix: camelize tuple bug

* fix: reverse transformers

* fix: transformers folder to camel

* fix: transformers as an object

* fix: linter error

* ci: run test with deno close #2701

* fix: test depends on build

* fix: deno import node:crypto

* fix: rest improvements

* fix: channel type

* fix: export user

* chore: move to unit dir

* test: moving bench

* fix: remove transformers from rest package

* fix: move toggle transformers to bot pkg

* fix: move out gw helpers to gw package

* test: add rest e2e test

* fix: syntex

* ci: add discord token

* fix: ci not passing secret

* test: add role test

* ci: fix secret inherit

* fix: role helpers transformer

* test: increase timeout to 10s

* fix: member helpers transformer

* test: add member test

* fix: name and type

* fix: guild ban

* test: fix test

* fix: test add await

* test: skip some test

* test: increase timeout

* chore: add transformer to import map

* fix: test

* test: add why-is-node-still-running

* test: add debug hook

* ci: add timeout incase any async running

* test: try fix

* test: turn on rest debug

* fix: if undefined

* test: reduce timeout

* fix: queue not running after some request

* fix: increase remaining after request without ratelimit header

* fix: partial webhook

* fix: fetch hooks not working if debug defined later

* fix: nickname null to undefined

* test: finish adding webhook test

* refactor(test): move rest to utils

* fix: add await

* fix: sticker

* feat: add message embed component transformer

* fix: test not done

* fix: arg type to bigString

* fix: sendMessage

* fix: add allowedMentions, interactionResponse

* test: add emoji e2e test

* test: add guild e2e test

* refactor(test): remove extra rest call

* fix: create emoji BINARY_TYPE_INVALID_DATA_URI

* fix: create guild rate limit

* fix: automode rule helpers and test

* fix: test run in only

* test: add some queue bucket test

* test: remove empty test

* refactor(test): use new guild

* test: use new guild for other test

* fix: guild not defind

* reactor(test): remove duplicated creat channel

* test: increase timeout to 30s

* test: add thread test

* fix: more transformers

* fix: gateway helpers use transformers

* fix: types belong in types pkg

* fix: helpers use transformers

* BREAKING: v19 rewrite to node + major improvements (#2703)

* fix: move all to old folder

* fix: cleanup types

* fix: more cleanup

* fix: more base cleanup

* fix: token dotenv

* fix: add base transformer

* fix: partial error handling

* fix: handle 429 rate limit

* test(rest): fix unit test

* fix(script): transform extension

* test: fix error and buffer

* feat: camelizer util

* fix: cleanup

* fix: rate limit queues and headers processing

* fix: rest exports

* fix: no more transformers

* fix: queue header null bug

* fix: add gateway package base

* fix: lint error

* fix: add prettier file

* fix: prettier is default fmtr

* fix: fmt shard file

* fix: fmt

* fix: types issue

* fix: remove unused consts

* fix: all import issues

* fix: import error

* fix: import ending with .js

* fix: remove transformers package

* Fix eslint (#2710)

* fix: typing of button component label to be optional (#2708)

* feat: add guild_connections to role tags and toggles (#2706)

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* Add lint checks and autofixing workflow (#2702)

* Add lint checks and autofixing workflow

* Update lint.yml

* Fix: use yarn instead npm

* fix: add ts to eslint_extensions

* fix: update dir

* fix: lint.yml format

Co-authored-by: Jonathan Ho <heiheiho000@gmail.com>

* fix: unused deps

* ci: fix e2e test not running

* chore: run yarn install

* test: this should run test

* feat: getCHannel

* feat: createEMji helper

* feat: collection class in util package

* fix: gateway bugs

* why on earth is this needed change

* fix: cleanup docs on collection

* Emoji rest methods (node-migration-clean) (#2713)

* feat: all emoji rest methods

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: stuff

* fix: bot types

* fix: remove logs

* fix: camelize all gateway payloads

* fix: remove todos

* fix: start deris

* fix: lint/ts errors except shard file

* thats 1 way to fix type errors

* yes (#2714)

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* feat: rest channel helpers

* Update release.yml

* Update release.yml

* ci: add build filter

* ci: fail fast false

* fix: complete webhook related helpers

* fix: follow announcement helper

* add forum helper

* add stage helpers

* add thread related helpers

* alphabetize

* cleanup webhook routes

* automod helpers

* scheduled events

* integrations helpers

* invite stuff incomplete

* dm channel and avatar url

* chore: move ts-node into package

* fix: importing esm

* fix: tris message helpers

* test(rest): add simplifyUrl test

* test(rest): add checkRateLimits test

* test(rest): add processRateLimitedPaths test

* test(rest): fix missing beforeEach

* test(utils): enable old test

* interaction helpers

* perf(utils): optimize snake to camel case conversion (#2717)

* perf(utils): optimize snake to camel case conversion

* fmt

* wont change much but still faster

* actually this was a stupid idea

* shh

* Fix(client): Fix typings. (#2716)

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* test: fix rest and utils test (#2723)

* test(utils): fix  cant import collection

* test(rest): await expect

* fix(utils): deno compactability

* test(utils): typing

* fix(utils): add return type

* Add rest helpers for templates (#2727)

* Add rest helpers for templates

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: remove frozenAt

* fix: cleanup templates

* ci: release to npm (#2725)

* ci: release to npm

* Update release.yml

* 🐛 - fix: types - slashcommands - add nsfw prop (#2731)

* feat(rest helpers): Add template and member helpers. (#2728)

* feat(rest helpers): Add template and member helpers.

* format code

* feat(rest): add template routes

* fix(rest): routes and runMethod

* fix(rest): try to fix most of type

Co-authored-by: H01001000 <heiheiho000@gmail.com>
Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* ci: fix release (#2732)

* fix: rest type errors

* fix: v19 begin

* fix: yarn lock

* chore: fix deps and script (#2733)

* fix: bug camelizer deleting letters

* fix: falsy token check

* fix: add frozenat check for queue

* fix: max stack trace error do to infinite loop

* fix: type error

* test(rest): fix missing import (#2734)

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* fix: file paths for imports

* fix: lastShardId should default to 0

* fix: use isomorphic ws

* test(rest): fix "TypeError: [Function] is not a thenable" (#2736)

* test(utils): add utils tests (#2737)

* test(utils): add urltobase64 test

* test(utils): add token test

* test(utils): fix missing import buffer

* test(utils): add casting test

* test(utils): add casting test

* test(utils): fix use correct function

* chore: make eslint error if missing .js extension (#2735)

* chore: eslint error if missing .js extension

* chore

* lint: fix missing .js error

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* fix: readme runtime list (#2739)

* Bot pkg (#2740)

* fix: bot pkg test

* Fix code style issues with ESLint

* Update Guild.ts

* Update Guild.ts

* Fix code style issues with ESLint

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: Jonathan Ho <heiheiho000@gmail.com>

* Update tsdoc.json (#2741)

Updates tsdoc.json to reflect the current packages.

* Interaction types - remove member,channel,role from value type (#2743)

https://discord.com/channels/785384884197392384/1067265182776176690/1068189883073572924

* Add missing types (#2742)

* Revert "fix: use isomorphic ws" (#2744)

This reverts commit ad306b0d0a.

* fix: interaction requests that sent without full url

* fix: lint issues

* fix: remote gateway test file

* fix: interaction response bug with body being invalid (#2746)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: interaction followup type (#2747)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: e2e exit bug (#2748)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: rest sending attachments files (#2749)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

* fix: image file sending

* Fix code style issues with ESLint

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: guild and role methods (#2751)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

* fix: image file sending

* Fix code style issues with ESLint

* guild and role methods

* Fix code style issues with ESLint

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* ci: add bot package (#2752)

* ci: add bot package

* ci: fix test

* e2e test stuff (#2754)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

* fix: image file sending

* Fix code style issues with ESLint

* guild and role methods

* Fix code style issues with ESLint

* fix: dont send heartbeat if socket is not open

* fix: remove logs

* fox: remove more logs

* fix some bugs in role tests

* Switch to after hook style

* hoti's speed snaker

* auto convert objects for discord

* Fix code style issues with ESLint

* fix: remove dup imports

* fix: i hate linters

* speeder

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* fix: delete guilds test (#2758)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

* fix: image file sending

* Fix code style issues with ESLint

* guild and role methods

* Fix code style issues with ESLint

* fix: dont send heartbeat if socket is not open

* fix: remove logs

* fox: remove more logs

* fix some bugs in role tests

* Switch to after hook style

* hoti's speed snaker

* auto convert objects for discord

* Fix code style issues with ESLint

* fix: remove dup imports

* fix: i hate linters

* speeder

* fix: tests delete guilds

* Fix code style issues with ESLint

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* chore: fix deps (#2757)

* ci/test: fix bot pkg e2e test (#2759)

* chore: fix script and update import map (#2761)

* chore: fix version script

* chore: update import map

* chore: fix ws import map

* chore: fix deno import map

* test: fix

* fix: more rest e2e tests (#2763)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

* fix: image file sending

* Fix code style issues with ESLint

* guild and role methods

* Fix code style issues with ESLint

* fix: dont send heartbeat if socket is not open

* fix: remove logs

* fox: remove more logs

* fix some bugs in role tests

* Switch to after hook style

* hoti's speed snaker

* auto convert objects for discord

* Fix code style issues with ESLint

* fix: remove dup imports

* fix: i hate linters

* speeder

* fix: tests delete guilds

* Fix code style issues with ESLint

* fix: easier to provide custom intents in bot

* fix: shutdown bot after test

* fix: add getGuild

* fix: multiple guild delete attempts

* fix: add emoji e2e tests

* fix: remaining old e2e rest tests

* Fix code style issues with ESLint

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* test: add gateway integration test (#2756)

* test: add gateway integration test

* test(gateway): fix connection test

* test(gateway): add heartbeat test

* ci: add integration test

* fix: add uWebSockets.js

* ci: add timeout

* test(utils): remove old test

* Revert "test(utils): remove old test"

This reverts commit 04fb6dd4b5.

* test(gateway): fix uws server

* test(gateway): fix type

* chore: update codecov flag

* test(gateway): remove dev code

---------

Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com>

* Update release.yml (#2768)

* fix: bot logger (#2769)

* fix: readme runtime list

* Fix code style issues with ESLint

* node 18

* fix: websocket import type

* fix: body for interaction requests

* fix: perma fix for type error in ci

* fix: followupmessage option type

* fix: e2e tests exit bug

* fix: color console logger

* fix: image file sending

* Fix code style issues with ESLint

* guild and role methods

* Fix code style issues with ESLint

* fix: dont send heartbeat if socket is not open

* fix: remove logs

* fox: remove more logs

* fix some bugs in role tests

* Switch to after hook style

* hoti's speed snaker

* auto convert objects for discord

* Fix code style issues with ESLint

* fix: remove dup imports

* fix: i hate linters

* speeder

* fix: tests delete guilds

* Fix code style issues with ESLint

* fix: easier to provide custom intents in bot

* fix: shutdown bot after test

* fix: add getGuild

* fix: multiple guild delete attempts

* fix: add emoji e2e tests

* fix: remaining old e2e rest tests

* Fix code style issues with ESLint

* fix: add bot.logger

* fix: make logger name capital

---------

Co-authored-by: Lint Action <lint-action@samuelmeuli.com>

* chore: update readme (#2772)

* chore: add coverage per pkg

* chore: add npm version

* chore: add test status

* chore: fix ci

* chore: fix ci

* ci: fix ci needs

* chore: add only push event

* style: remove import logger

* 📚 - docs: fix README package links (#2773)

* test(all): add test importing index (#2774)

* test(all): add test importing index

* chore: remove old benchmark dir

* chore: disable coverage status fail

* test(client): add import test with try catch

* test(rest): fix narrow import scope

* test(utils): add test (#2764)

* test(utils): remove old test

* test(utils): add color test

* test(utils): fix import mocha

* test(utils): fix test type error

* test(utils): remove dev code

* fix(utils): bucket not export all function

* test(utils): add some test for bucket

* fix(utils): close #2775

* test(utils): add test for permissions.ts

* test(utils): fix missing mocha import

* fix(utils): better fix for #2775

* feat: addReaction & addReactions

* feat: connectToVoice

* fix: linters issues

* fix: remove aliases and add createGuildFromTemplate

* feat: deleteMessages

* fix: reaction related helpers

* mfa level

* voie states editing

* image urls

* fix: typos

* get message typeguards

* fix: more helpers

* fix: remaining helpers

* fix: add logs to gateway manager

* fix: rest resolve sends status and body

* fix: lots of errors

* fix: client errors

* fix: remove old pkg

* snaker

* fix: broken util import for image url

* fix: cleanup shard and circular deps

* fix: remove ThreadChannel from GuildChannel

* fix: generate interaction usage

* fix: more bugs

* fix: use node:events to import

* fix(rest): add interface RestRequestRejection (#2782)

* fix: remove invalid todo

* fix: timeout bug

---------

Co-authored-by: Skillz <skillz@discord.gg/ddeno>
Co-authored-by: Jonathan Ho <heiheiho000@gmail.com>
Co-authored-by: deepsarda <92147339+deepsarda@users.noreply.github.com>
Co-authored-by: Awesome Stickz <awesome@stickz.dev>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: Lars_und_so <46791248+Larsundso@users.noreply.github.com>
Co-authored-by: ITOH <to@itoh.at>
Co-authored-by: Yaikava <83710104+Yaikava@users.noreply.github.com>
Co-authored-by: Andreas Fink <mail@afink.dev>

---------

Co-authored-by: Jonathan Ho <48591478+H01001000@users.noreply.github.com>
Co-authored-by: H01001000 <heiheiho000@gmail.com>
Co-authored-by: deepsarda <92147339+deepsarda@users.noreply.github.com>
Co-authored-by: Yaikava <83710104+Yaikava@users.noreply.github.com>
Co-authored-by: Skillz <skillz@discord.gg/ddeno>
Co-authored-by: Awesome Stickz <awesome@stickz.dev>
Co-authored-by: Lint Action <lint-action@samuelmeuli.com>
Co-authored-by: Lars_und_so <46791248+Larsundso@users.noreply.github.com>
Co-authored-by: ITOH <to@itoh.at>
Co-authored-by: Andreas Fink <mail@afink.dev>
2023-02-20 15:00:00 -06:00

16 KiB

sidebar_position
sidebar_position
4

Migrating

Migrating from Discord.js

This migration guide is not intended to discredit Discord.js authors/maintainers or Discord.js itself. In fact, Discord.js is the most popular Node.js library, admired and praised by a lot of JavaScript developers.

Finding an Open-Source Discord Bot

For the purposes of this guide, I wanted to find a moderation bot that is totally open source to show an example of how to convert the bot to Discordeno. Trying to find one was not easy as most bot's were not using the latest Discord.JS version 12. Trying to find one that was using TypeScript made it even more difficult. My next best solution was to find a moderation bot that was recently updated(showing it is maintained or recently built). The best one I could find was Zodiac Bot.

For the purposes of this guide, I will be using the current latest commit

Preparations

  • First, create a Discordeno Bot using the Generator Template I will name it Zodiac.

  • Then git clone https://github.com/Skillz4Killz/Zodiac.git

Now that I had the repository cloned, I could begin. Note that although the bot we are converting is built in JavaScript, I converted all code to TypeScript in this Guide as Discordeno is designed to be the best lib for TypeScript developers.

Time to get started!

Converting main.js (index file)

The first thing is to convert the main.js file which would be the app.js or index.js file. This is the file that is run to start your bot. In this case, the bot developer chose main.js. In Deno, the initial file is named mod.ts so we can go ahead and opt for the Deno pattern. Note: there is already a mod.ts file created and prebuilt entirely using the Generator.

Current Discord.JS Code:

/* Keeping this to shoutout/credit the original author <3
* @author: nukestye
*/

const config = require("./config.json");
const fs = require("fs");
const log = console.log;

// Setting up the way to get commands
const { CommandoClient } = require("discord.js-commando");
const path = require("path");

// reading events
fs.readdir("./src/events/", (err, files) => {
  if (err) return console.error(err);
  files.forEach((file) => {
    const eventFunction = require(`./src/events/${file}`);
    if (eventFunction.disabled) return;
    const event = eventFunction.event || file.split(".")[0];
    const emitter =
      (typeof eventFunction.emitter === "string" ? client[eventFunction.emitter] : eventFunction.emitter) || client;
    const { once } = eventFunction;
    try {
      emitter[
        once ? "once" : "on"
      ](event, (...args) => eventFunction.run(...args));
    } catch (error) {
      console.error(error.stack);
    }
  });
});

const client = global.client = new CommandoClient({
  commandPrefix: `${config.prefix}`,
  owner: `${config.owner}`,
  invite: `${config.discord}`,
  unknownCommandResponse: false,
});

// Registing the commands
client.registry
  .registerDefaultTypes()
  // The different fields for cmds
  .registerGroups([
    ["mod", "Moderation Commands"],
    ["public", "Public Commands"],
  ])
  .registerDefaultGroups()
  // Basic cmds can be disabled like {"cmd: false"}
  .registerDefaultCommands()
  // commands in "/src/commands" will be counted
  .registerCommandsIn(path.join(__dirname, "/src/commands"));

// list of activities that the bot goes through
const activityArray = [`${config.prefix}help | `];
// Bot lanuch code
client.once("ready", () => {
  log(`Logged in as ${client.user.tag} in ${client.guilds.size} guild(s)!`);
  setInterval(() => {
    const index = Math.floor(Math.random() * (activityArray.length)); // generates a random number between 1 and the length of the activities array list
    client.user.setActivity(
      activityArray[index],
      {
        type: "PLAYING",
      },
    ); // sets bot"s activities to one of the phrases in the arraylist.
  }, 5000); // updates every 10000ms = 10s
});
// If an error print it out
client.on("error", console.error);

// Login in using the token in config
client.login(config.env.TOKEN);

Discordeno Version:

import { botCache, Intents } from "./deps.ts";
import { configs } from "./configs.ts";
import { importDirectory } from "./src/utils/helpers.ts";
import { loadLanguages } from "./src/utils/i18next.ts";

console.info(
  "Beginning Bot Startup Process. This can take a little bit depending on your system. Loading now...",
);

// Always require these files be processed before anything else
await Promise.all([
  "./src/customizations/structures",
].map(
  (path) => importDirectory(Deno.realPathSync(path)),
));

// Forces deno to read all the files which will fill the commands/inhibitors cache etc.
await Promise.all(
  [
    "./src/commands",
    "./src/inhibitors",
    "./src/events",
    "./src/arguments",
    "./src/monitors",
    "./src/tasks",
    "./src/permissionLevels",
    "./src/events",
  ].map(
    (path) => importDirectory(Deno.realPathSync(path)),
  ),
);

// Loads languages
await loadLanguages();
await import("./src/database/database.ts");

startBot({
  token: configs.token,
  // Pick the intents you wish to have for your bot.
  // For instance, to work with guild message reactions, you will have to pass the Intents.GUILD_MESSAGE_REACTIONS intent to the array.
  intents: Intents.Guilds | Intents.GuildMessages,
  // These are all your event handler functions. Imported from the events folder
  events: botCache.events,
});

Something we haven't converted yet from the main.js files is the event listeners. To do that, we will open up the events folder and find the corresponding event or create it if necessary. In this case, we have the ready event and there is already a ready.ts file. We can just use that.

In our ready.ts file we can add the ready event listener.

import { ActivityTypes, botCache, cache, chooseRandom, editBotStatus, StatusTypes } from "../../deps.ts";
import { registerTasks } from "./../utils/taskHelper.ts";

botCache.events.ready = function () {
  editBotStatus(
    StatusTypes.DoNotDisturb,
    "Discordeno Best Lib",
    ActivityTypes.Game,
  );

  console.log(`Loaded ${botCache.arguments.size} Argument(s)`);
  console.log(`Loaded ${botCache.commands.size} Command(s)`);
  console.log(`Loaded ${Object.keys(botCache.events).length} Event(s)`);
  console.log(`Loaded ${botCache.inhibitors.size} Inhibitor(s)`);
  console.log(`Loaded ${botCache.monitors.size} Monitor(s)`);
  console.log(`Loaded ${botCache.tasks.size} Task(s)`);

  registerTasks();

  console.log(
    `[READY] Bot is online and ready in ${cache.guilds.size} guild(s)!`,
  );

  // list of activities that the bot goes through
  const activityArray = [`${configs.prefix}help | `];
  setInterval(() => {
    const randomActivity = activityArray[Math.floor(Math.random() * activityArray.length)];

    editBotStatus(botCache, {
      activities: [{ name: randomActivity, type: ActivityTypes.Game, createdAt: Date.now() }],
      status: "online",
    });
  }, 5000);
};

To understand this code, we are setting a function to be run when the bot is ready. Then the bot will edit the bot's status every 5 seconds. Notice that you also have beautiful enums provided that prevents you from making any typos/mistakes.

We have now converted the entire main.js file, in a matter of seconds. The Discordeno official generator took care of the majority of workload and we just modified the ready.ts file.

Note: I did remove some generally well known "bad practices" such as global vars and such. Overall, you will see the functionality of the project will not change as we progress through this guide.

Converting Commands

The first command in the commands folder is the addRole command.

This is the code from the bot:

// Getting the 'Command' features from Commando
const { Command } = require("discord.js-commando");

// Code for the command
module.exports = class addRoleCommand extends Command {
  constructor(client) {
    super(client, {
      // name of the command, must be in lowercase
      name: "addrole",
      // other ways to call the command, must be in lowercase
      aliases: ["role"],
      // command group its part of
      group: "mod",
      // name within the command group, must be in lowercase
      memberName: "addrole",
      // Is the description used for 'help' command
      description: "Adds mentioned role to mentioned user.",
      // Prevents it from being used in dms
      guildOnly: true,
      // Permissions, list found here > `discord.js.org/#/docs/main/11.5.1/class/Permissions?scrollTo=s-FLAGS`
      clientPermissions: ["ADMINISTRATOR", "MANAGE_ROLES"],
      userPermissions: ["MANAGE_ROLES"],
      // Prevents anyone other than owner to use the command
      ownerOnly: false,
    });
  }

  // Run code goes here
  run(message) {
    const user = message.mentions.members.first();
    const roleToAdd = message.mentions.roles.first();

    // checking to see if the user has the role or not
    if (!(user.roles.find((r) => r.name === roleToAdd.name))) {
      user.addRole(roleToAdd);
      message.channel.send(`${user} has been given the role: ${roleToAdd.name}`)
        .then((msg) => {
          msg.delete(5000);
        });
    } else {
      message.channel.send(`${user} already has the role: ${roleToAdd.name}`);
    }

    // console.error(user, roleToAdd, message.member.roles.find(r => r.name === roleToAdd));
  }
};

This is how to do it with Discordeno:

import { createCommand } from "./../../utils/helpers.ts";

createCommand({
  name: "role",
  // Oher ways to call the command
  aliases: ["addrole"],
  // Is the description used for 'help' command
  description: "Adds mentioned role to mentioned user.",
  // Prevents it from being used in dms
  guildOnly: true,
  botServerPermissions: ["ADMINISTRATOR", "MANAGE_ROLES"],
  userServerPermissions: ["MANAGE_ROLES"],
  arguments: [
    { name: "member", type: "member" },
    { name: "role", type: "role" },
  ],
  execute: (bot, message, args) => {
    // checking to see if the user has the role or not
    if (!args.member.roles.includes(args.role.id)) {
      bot.helpers.addRole(message.guildId, args.member.id, args.role.id);
      bot.helpers.sendMessage(message.channelId, {
        content: `${args.member.mention} has been given the role: ${args.role.name}`,
      });
    } else {
      bot.helpers.sendMessage(message.channelId, {
        content: `${args.member.mention} already has the role: ${args.role.name}`,
      });
    }
  },
});

Awesome, that is a full command converted from Discord.JS to Discordeno. See how easy it is! Let's convert one more command to see how to really take full advantage of Discordeno template and have something amazing.

Discord.JS Kick Command Version

// Getting the 'Command' features from Commando
const { Command } = require("discord.js-commando");
const { RichEmbed } = require("discord.js");
const chalk = require("chalk");
const log = console.log;

// Code for the command
module.exports = class kickCommand extends Command {
  constructor(client) {
    super(client, {
      // name of the command, must be in lowercase
      name: "kick",
      // other ways to call the command, must be in lowercase
      aliases: ["boot", "tempban"],
      // command group its part of
      group: "mod",
      // name within the command group, must be in lowercase
      memberName: "kick",
      // Is the description used for 'help' command
      description: "Kick command.",
      // adds cooldowns to the command
      throttling: {
        // usages in certain time x
        usages: 1,
        // the cooldown
        duration: 10,
      },
      // Prevents it from being used in dms
      guildOnly: true,
      // Permissions, list found here > `discord.js.org/#/docs/main/11.5.1/class/Permissions?scrollTo=s-FLAGS`
      clientPermissions: ["ADMINISTRATOR"],
      userPermissions: ["KICK_MEMBERS"],
      // Prevents anyone other than owner to use the command
      ownerOnly: false,
    });
  }

  // Run code goes here
  run(message) {
    const messageArry = message.content.split(" ");
    const args = messageArry.slice(1);

    const kUser = message.guild.member(
      message.mentions.users.first() || message.guild.get(args[0]),
    );
    if (!kUser) return message.channel.send("User cannot be found!");
    const kreason = args.join(" ").slice(22);

    // setting up the embed for report/log
    const kickEmbed = new RichEmbed()
      .setDescription(`Report: ${kUser} Kick`)
      .addField("Reason >", `${kreason}`)
      .addField("Time", message.createdAt);

    const reportchannel = message.guild.channels.find("name", "report");
    if (!reportchannel) {
      return message.channel.send("*`Report channel cannot be found!`*");
    }

    // Delete the message command
    // eslint-disable-next-line camelcase
    message.delete().catch((O_o) => {});
    // Kick the user with reason
    message.guild.member(kUser).kick(kreason);
    // sends the kick report into log/report
    reportchannel.send(kickEmbed);
    // Logs the kick into the terminal
    log(chalk.red("KICK", chalk.underline.bgBlue(kUser) + "!"));
  }
};

Discordeno Version

import { createCommand } from "./../../utils/helpers.ts";

createCommand({
  name: `kick`,
  aliases: ["boot", "tempban"],
  description: "Kick command.",
  // adds cooldowns to the command
  cooldown: {
    // usages in certain duration of seconds below
    allowedUses: 1,
    // the cooldown
    seconds: 10,
  },
  // Prevents it from being used in dms
  guildOnly: true,
  botServerPermissions: ["ADMINISTRATOR"],
  userServerPermissions: ["KICK_MEMBERS"],
  arguments: [
    {
      name: "member",
      type: "member",
      missing: function (message) {
        message.reply(`User cannot be found.`);
      },
      // By default this is true but for the purpose of the guide so you can see this exists.
      required: true,
    },
    {
      name: "reason",
      // The leftover string provided by the user that was not used by previous args.
      type: "...string",
      defaultValue: "No reason provided.",
      // It is silly to lowercase this but for the purpose of the guide you can see that this is also available to you.
      lowercase: true,
    },
  ],
  execute: function (bot, message, args: KickArgs) {
    // setting up the embed for report/log
    const embed = new Embed()
      .setDescription(`Report: ${args.member.mention} Kick`)
      .addField("Reason >", args.reason)
      .addField("Time", message.timestamp.toString());

    const reportchannel = message.guild?.channels.find((channel) => channel.name === "report");
    if (!reportchannel) {
      return bot.helpers.sendMessage(message.channelId, { content: "*`Report channel cannot be found!`*" });
    }

    // Delete the message command
    bot.helpers.deleteMessage(message.channelId, { content: "Remove kick command trigger." });
    // Kick the user with reason
    bot.helpers.kickMember(message.guildId, args.member.id, args.reason);
    // sends the kick report into log/report
    bot.helpers.sendMessage(message.channelId, { embeds: [embed] });
  },
});

interface KickArgs {
  member: Member;
  reason: string;
}

Let's take a minute and explain the differences here. The first thing you will probably notice is different is the arguments property. Discordeno provides the arguments property because it provides argument handling/parsing/validating internally. You don't need to be splitting the message content or going through and validating it yourself. All you do is tell Discordeno that you want a member and a reason. It will do the magic and hard work to get you that data before you even run the command. You just do args.member and you have access to the full member object. There are a lot more powerful aspects to Discordeno like arguments. Keep diving in and you will find all the wonderful tools available to give you the best developer experience possible.

Need More Examples/Help

If you still need more help converting other aspects of your bot please contact me at Discord. I will continue adding more examples to this guide as more people request them.