npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

discordts-decorators

v1.2.7

Published

A simple library to create discord bots using typescript TC39 decorators with discord.js.

Downloads

102

Readme

discordts-decorators

A discordjs package that uses TC39 decorator pattern. This package is a wrapper for discord.js that allows you to use decorators to create commands and events.

Examples

Command

import { Injections } from "discordts-decorators";
import { CommandInteraction } from "discord.js";

const { Discord, Command, Autocomplete } = Injections();

@Discord
export class Fun {
  // Read the documention for more information
  // on how to use integration_types and context
  // https://discord.com/developers/docs/interactions/application-commands#interaction-contexts
  public static integration_types = [0, 1];
  public static context = [0, 1, 2];

  @Command('Ping the bot')
  public static async ping(interaction: CommandInteraction) {
    const { createdTimestamp } = interaction;
    const reply = await interaction.editReply('Pinging...');
    const messagePing = reply.createdTimestamp - createdTimestamp;
    const websocketPing = interaction.client.ws.ping;

    await interaction.editReply(`Pong!\n**Message Ping:** ${messagePing}ms\n**Websocket Ping:** ${websocketPing}ms`);
  }

  @Command('Autocomplete test', 10, true)
  @Autocomplete('test', 'Test autocomplete', true)
  public static async autocompletetest(interaction: CommandInteraction | AutocompleteInteraction) {
    if (interaction.isAutocomplete()) {
      // @ts-ignore
      await interaction.respond([
        {
          name: 'Test 1',
          value: 'test1'
        },
        {
          name: 'Test 2',
          value: 'test2'
        }
      ]);
    }
  }
}

Event

import {
  Collection,
  CommandInteraction,
  CommandInteractionOptionResolver,
  InteractionDeferReplyOptions
} from 'discord.js';
import { Injections } from 'discordts-decorators';

const { Discord, Event } = Injections();

@Discord
export class EventManager {
  @Event()
  public static async ready() {
    console.log('Client is ready!');
  }

  @Event()
  public static async error(error: Error) {
    console.error(error);
  }

  @Event()
  public static async interactionCreate(interaction: CommandInteraction) {
    const { client } = interaction;
    const subcommmand = (interaction.options as CommandInteractionOptionResolver).getSubcommand();
    const commandName = interaction.commandName;

    console.log(`Command: ${commandName} | Subcommand: ${subcommmand}`);

    // console.log(client.commands)
    const subcommands = client.commands.get(commandName).options;
    const command = subcommands.find((cmd) => cmd.name === subcommmand);
    if (!command) return;

    if (interaction.isAutocomplete()) {
      try {
        await command.autocomplete(interaction);
      } catch (error) {
        console.error(error);
      }

      return;
    }

    // Cooldowns handling
    const cooldowns = client.cooldowns;
    if (!cooldowns.has(command.name)) {
      cooldowns.set(command.name, new Collection<string, string>());
    }

    const now = new Date().getTime();
    const timestamps = cooldowns.get(command.name);
    const cooldownAmount = command.cooldown * 1000;
    if (timestamps.has(interaction.user.id)) {
      const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;
      if (now < expirationTime) {
        const timeLeft = Math.round((expirationTime - now) / 1000);
        return interaction.reply({
          content: `Please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command.name}\` command.`,
          ephemeral: true
        });
      }
    }

    timestamps.set(interaction.user.id, now);
    setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);
    // End of cooldowns handling

    // Command execution
    if (interaction.isCommand()) {
      try {
        await interaction.deferReply({ ephemeral: command.ephemeral || false } as InteractionDeferReplyOptions);
        setTimeout(() => {
          if (!interaction.replied) {
            interaction.editReply('This interaction has expired.');
            return;
          }
        }, 10000);
        await command.run(interaction);
      } catch (error) {
        console.error(error);
        await interaction.editReply('There was an error while executing this command!');
      }
    }
  }
}

export default EventManager;

Bot Initialization

import {IntentsBitField} from "discord.js";
import { BotManager } from "discordts-decorators";
import EventManager from "./events/EventManager.js";
import Commands from "./commands/index.js";

const intents = new IntentsBitField([
  'Guilds',
  'GuildMembers',
  'GuildMessages',
  'GuildMessageReactions',
  'GuildModeration',
  'GuildPresences',
  'GuildInvites',
  'DirectMessages',
  'DirectMessageReactions',
  'MessageContent',
]);

const DiscordBot = BotManager.getInstance();

DiscordBot.setPrivateData({
  id: 'bot id',
  token: 'bot token',
  intents,
  name: 'VeryCoolName',
}).create(EventManager);

for (const command of Commands) {
  DiscordBot.create(command);
}

await DiscordBot.buildClient();
await DiscordBot.login();
DiscordBot.setPresence('idle', {
  name: 'with discordts-decorators',
});

Version

1.2.7

- Old command system is now deprecated
- Use new Event Handler
- Commands use commands instead of subcommands

1.2.62

- Fixed bug with autocomplete

1.2.6

- Fixed log for commands and events
- Autocomplete decorator

1.2.5

- Added ability to `removeGuildCommands` using BotManager

1.2.42

- Revert log for commands and events

1.2.4

- Debug mode on global.Config.debug (default false)
- Added debug log for commands and events

1.2.3

- Moved context and integration to command instead of subcommand
- Added context/integration to variables

1.2.2

- Fixed context and integration with discord.js
- Fixed log for events/commands classes

1.2.0

- Added support for installable user applications
- Added context to commands

1.1.12

- Added guild refresh commands

1.1.11

- Release new build

1.1.1

- Set metadata on options to be optional

1.1.0

- Added better logging for commands and events
- Added better error handling for commands and events
- Moved choices, max_length, and min_length to metadata.choices, metadata.max_length, and metadata.min_length
- Update typings for new discord.js version

1.0.0

- Initial release