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

sabr

v0.1.15

Published

Klasa Discord API Library Framework

Downloads

6

Readme

Sabr

A Klasa Discord API Library Framework.

Note: The official Klasa framework is a lot more powerful, in-depth and a lot more feature packed.

If you still interested in using this framework keep reading below:

Usage Getting Started

npm i sabr @klasa/core

Create an index.ts file and paste the code below:

import BotClient from "sabr";
// This is your config file to help keep your bot token and other info you want SECRET. Never hard code your tokens.
import config from "./config";

export const client = new BotClient(config.token, {
  rest: {
    offset: 0,
  }
})
// To set a default prefix for the bot
.setDefaultPrefix("%")
// To load your commands, monitors, tasks etc... These paths will be cached and reloaded when you use the reload command
.loadDirectories([
  `${__dirname}/commands/`,
  `${dirname}/monitors/`,
  `${dirname}/tasks`,
]);

These are all the client options available from Sabr.

  /** Whether the core commands and library should respond use embeds. By default this is enabled. */
  useEmbeds?: boolean;
  /** The core commands that you would like to disable */
  disabledCoreCommands?: ("info" | "invite" | "ping" | "reload" | "stats")[];

As soon as you start your bot, you will realize that Klasa's framework is different. For example, Klasa will make folders like monitors/tasks/arguments/providers etc... Sabr will not create these. Sabr will only use what you provide it.

Commands

Commands are a bit different in Sabr as well. In Sabr, they are added by running a function as opposed to creating a new class that extends the command class. First, let's review all the command options available:

  /** The command names that can also trigger this command. */
  aliases?: string[];
  /** Whether or not this command can be used in DM. */
  dm?: boolean;
  /** List of modules that you can use to enable/disable certain modules of your bots on a server. */
  modules?: string[];
  /** The permission level required to run this command. */
  permissionLevel?: (message: Message) => boolean;
  /** The description of the command. Useful for a help command to provide information on the command. */
  description?: string;
  /** The permissions you want to check if the message author has from their roles. */
  requiredServerPermissions?: PermissionsFlags[];
  /** The permissions you want to check if the message author has in this channel where the command is used. */
  requiredChannelPermissions?: PermissionsFlags[];
  /** The permissions the BOT must have from it's roles. */
  botServerPermissions?: PermissionsFlags[];
  /** The permissions the BOT must have in the current channel. */
  botChannelPermissions?: PermissionsFlags[];
  /** The arguments that a command should have with arg parsing built in. */
  arguments?: Argument[];
  /** The main code that will be run when this command is triggered. */
  execute: (message: Message, parameters: unknown) => unknown;

These are the options for the command arguments:

  /** The name of the argument. Useful for when you need to alert the user X arg is missing. */
  name: string;
  /** The type of the argument you would like. Defaults to string. */
  type?: "number" | "string" | "boolean" | "subcommand";
  /** The function that runs if this argument is required and is missing. */
  missing?: (message: Message) => unknown;
  /** Whether or not this argument is required. Defaults to true. */
  required?: boolean;
  /** If the type is string, this will force this argument to be lowercase. */
  lowercase?: boolean;
  /** If the type is string or subcommand you can provide literals. The argument MUST be exactly the same as the literals to be accepted. For example, you can list the subcommands here to make sure it matches. */
  literals?: string[];
  /** The default value for this argument/subcommand. */
  defaultValue?: string | boolean | number

Here is a very basic example:

client.createCommand("ping", {
  aliases: ["pong"],
  description: "Hmm some silly description",
  botChannelPermissions: [PermissionsFlags.SendMessages],
  execute: (message) => {
    client.sendMessage(message.channel.id, { content: "Shut up" });
  },
})

Here is a bit more complex example, with a subcommand example. Notice how you can simply chain subcommands 1 after another. Each subcommand is it's own command instance allowing you to have custom aliases per subcommand, arguments per subcommand, unique permission levels, required permissions etc...

client.createCommand("ping", {
  aliases: ["pong"],
  dm: false,
  description: "Hmm some silly description",
  permissionLevel: (message) => message.member!.permissions.has(PermissionsFlags.Administrator),
  botChannelPermissions: [PermissionsFlags.SendMessages],
  arguments: [
    {
      name: "subcommand",
      type: "subcommand",
      literals: ["subcommand"],
    },
  ],
  execute: (message) => {
    client.sendMessage(message.channel.id, { content: "Shut up" });
  },
})
// Add a subcommand example with a custom alias, permissions and description
  .createSubcommand("ping", "subcommand", {
    aliases: ["sub"],
    description: "Hmm some silly description for the sub",
    botChannelPermissions: [PermissionsFlags.SendMessages],
    execute: (message) => {
      client.sendMessage(message.channel.id, { content: "Shut up, from subway eat freshs" });
    },
  });

Let's try and note a few more differences. Notice how you no longer need to explicitly type the execute: (message) as execute: (message: Message) saving you imports. Sabr can automatically infer these because it is not using extended classes but pure functions. Also notice that permissionLevel is a function as opposed to a number like in Klasa. Subcommands are done by a function as well, meaning you can even refactor code enough so that every subcommand has its own file or u can have multiple related commands in the same file. Another difference that is not entirely obvious in the example above is that the command args are provided as an object instead of an array. To see this in action, let's see another example:

interface PingCommandArgs {
  amount?: number;
  reason: string;
}

client.createCommand("ping", {
  aliases: ["pong"],
  dm: false,
  description: "Hmm some silly description",
  botChannelPermissions: [PermissionsFlags.SendMessages],
  arguments: [
    {
      name: "amount",
      type: "number"
    },
    {
      name: "reason",
      type: "string",
      required: true,
      lowercase: true
    }
  ],
  execute: (message, args: PingCommandArgs) => {
    /**
     * Assuming we use the following command usage: `.ping REASON`
     * args.amount will be undefined
     * args.reason will be `test reason`
     *
     * Assuming we use the following command usage: `.ping 5 REASON`
     * args.amount will be 5
     * and args.reason will be `test reason`
     *
     */
    if (!args.amount) {
      // Handle when amount is not provided.
    }

    client.sendMessage(message.channel.id, { content: `Shut up, ${args.reason}` });
  },
})

Monitors

Monitors in Sabr are also done through a functional approach as opposed to a class based approach. Sabr also has a few different default options that rely on most used values as opposed to ignoring everything by default.

client.createMonitor("name", {
  execute: (message) => {
    client.sendMessage(message.channel.id, { content: "Monitor is working for sure for sure" });
  },
});

  /** Monitor Options */

  /** Whether this monitor should ignore messages that are sent by bots. By default this is true. */
  ignoreBots?: boolean;
  /** Whether this monitor should ignore messages that are sent by others. By default this is false.*/
  ignoreOthers?: boolean;
  /** Whether this monitor should ignore messages that are edited. By default this is false.*/
  ignoreEdits?: boolean;
  /** Whether this monitor should ignore messages that are sent in DM. By default this is true. */
  ignoreDM?: boolean;
  /** The permissions you want to check if the message author has from their roles. */
  requiredServerPermissions?: PermissionsFlags[];
  /** The permissions you want to check if the message author has in this channel where the command is used. */
  requiredChannelPermissions?: PermissionsFlags[];
  /** The permissions the BOT must have from it's roles. */
  botServerPermissions?: PermissionsFlags[];
  /** The permissions the BOT must have in the current channel. */
  botChannelPermissions?: PermissionsFlags[];

Sabr has almost all the same ignore options except the blacklisted ones as those require settings and Sabr stays away from creating default settings so that you can control your database as you wish. There are also permission options similar to commands allowing you to handle permissions much easier.

Tasks

Tasks are a bit different from Klasa Tasks in that Sabr tasks are repeating. Doing a task for a 1 time unmute is not an option(klasa is able to do this because it has access to settings that it controls). Instead, the same functionality can be accomplished by just handling unmutes in a simple unmute task that handles all ur unmute needs.

client.createTask('unmute', {
  interval: 12000,
  execute: () => {
    const now = Date.now()
    client.mutedUsers.forEach(mutedUser => {
      if (now < mutedUser.timestamp) return;
      // Remove the muted role from use
      handleUnmute(mutedUser)
    })
  }
})

Notice that in that example we provided a interval of 120,000 ms which is 2 minutes. However, this is just to show an example of how to provide an interval. By default the interval is 60000 ms. By not having access to settings like Klasa does, there is a small downside of not being able to accurately time tasks to run. For example, if you had a task that ran every 20 minutes and it ran at 5:00. Then you restarted the bot at 5:05. The task would run at 5:25. To solve this, Sabr provides you the ability to customize the task initilization once you have your settings prepared as you like. When the "READY" event is fired, Sabr runs the client.loadTasks() function. By overriding this function you can enhance this functionality if you so desire. For the average bot developer, this is not usually needed for most use cases in my experience.