Giter VIP home page Giter VIP logo

gatekeeper's Introduction

This project is deprecated

TL;DR: Use Reacord

I'm moving away from this project's development for a few reasons:

  • The command handling part is limited, and doesn't accomodate the use cases that a decent portion of bots need, e.g. being able to add a command for individual guilds
  • The reactivity part has gaps, and also makes you use it everywhere with no opt-out

For that reason, I split out the reactivity part into a new library: Reacord. It allows you to leverage JSX, react state, as well as the react ecosystem, and is much more powerful than what gatekeeper offers to accomplish the same goal. I would recommend using Reacord if you want declarative, highly interactive messages.

For command handling, I can't recommend a library for that (yet?), but you can build your own simple command handler: (1) (2)

gatekeeper

Gatekeeper is a ✨reactive✨ interaction framework for discord.js!

Install:

# npm
npm install @itsmapleleaf/gatekeeper discord.js

# yarn
yarn add @itsmapleleaf/gatekeeper discord.js

# pnpm
pnpm add @itsmapleleaf/gatekeeper discord.js

Here's a taste of what Gatekeeper looks like:

import { buttonComponent, Gatekeeper } from "@itsmapleleaf/gatekeeper"
import { Client, Intents } from "discord.js"

const client = new Client({
  intents: [Intents.FLAGS.GUILDS],
})

;(async () => {
  const gatekeeper = await Gatekeeper.create({
    client,
  })

  gatekeeper.addSlashCommand({
    name: "counter",
    description: "make a counter",
    run(context) {
      let count = 0

      context.reply(() => [
        `button pressed ${count} times`,
        buttonComponent({
          style: "PRIMARY",
          label: "press it",
          onClick: () => {
            count += 1
          },
        }),
      ])
    },
  })

  await client.login(process.env.BOT_TOKEN)
})()

And a silly example, demonstrating the power of the library. You can find the code here

showcase

gatekeeper's People

Contributors

crawron avatar itsmapleleaf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

gatekeeper's Issues

Allow accessing underlying interaction as an escape hatch

Currently, there is no way (that I know of) to access the underlying interaction on a slash command. This would be useful in order to perform actions not yet supported by gatekeeper (eg: #18), without losing gatekeeper's niceties like auto-syncing commands.

Maybe expose it as a something like readonly nativeInteraction: Interaction, to use the react convention for event handlers?

Ephemeral replies can't be edited

Currently, context.ephemeralReply returns void because:

This does not return a reply handle; ephemeral replies can't be updated or deleted manually
— interaction-context.ts:52

However, I did a little testing and it seems to update just like regular replies. Maybe there was an API update since then?

Here's my test code:

import assert from "assert";
import { Client, Intents } from "discord.js";
import { setTimeout } from "timers/promises";
import { GUILD_ID, TOKEN } from "../src/config";

console.clear();

const client = new Client({
  intents: [Intents.FLAGS.GUILD_VOICE_STATES, Intents.FLAGS.GUILDS],
});
client.login(TOKEN);

client.on("ready", async () => {
  const acm = client.application?.commands;
  assert(acm);

  const cmd = await acm.create(
    {
      type: "CHAT_INPUT",
      name: "edit-reply",
      description: "Editind ephemeral reply",
    },
    GUILD_ID!,
  );
});

client.on("interactionCreate", async (interaction) => {
  assert(interaction.isApplicationCommand());

  await interaction.deferReply({ ephemeral: true });

  await setTimeout(1_000);

  await interaction.editReply({
    embeds: [{ color: "RED", description: "First reply" }],
    // prettier-ignore
    components: [
      {type: "ACTION_ROW", components: [
        {type: "BUTTON", disabled: true, style: "PRIMARY", label: "Am I enabled?", customId: "btn"},
      ]},
    ],
  });

  await setTimeout(1_000);

  await interaction.editReply({
    embeds: [{ color: "AQUA", description: "Edited reply" }],
    // prettier-ignore
    components: [
      {type: "ACTION_ROW", components: [
        {type: "BUTTON", disabled: false, style: "PRIMARY", label: "I'm enabled!", customId: "btn"},
      ]},
    ],
  });
});

Add extra context argument for commands loaded through files

This argument would be passed in from the constructor:

// bot-context.ts
type BotContext = {
  message: string
}
// main.ts
await Gatekeeper.create<BotContext>({
  client,
  commandFolder: join(dirname(fileURLToPath(import.meta.url)), "commands"),
  context: { message: "hi" },
})
// commands/message.ts
export default function addCommands(
  gatekeeper: Gatekeeper,
  { message }: BotContext,
) {
  gatekeeper.addCommand({
    name: "message",
    description: "sends a message",
    async run(context) {
      context.reply(message)
    },
  })
}

This would allow passing values around through commands without having to use globals

Accept glob for command files

A lot more flexible than just accepting a folder path.

Would probably be in the form of an option:

Gatekeeper.create({
	client,
	commandFiles: './**/*.command.ts',
})

Improve handler logic

At the moment, every time a command gets run, it registers a new listener in Discord.JS to listen for message component interaction events. Listeners get removed after 15 minutes, but this can still show the "10 max listeners exceeded" warning in Node.JS. Need to refactor the structure of things to handle all component interactions through one interaction event listener

Stickers

Do bots even actually send these? ...eh, logging it anyhow. stickerComponent.

Message files

This can come in the form of a fileComponent, rendered once for each file to attach.

Persistent command instances

After a bot restarts, the messages it previously created become "inactive", and it can no longer respond to them. It'd be a cool feature to allow instances to persist, somehow. Might require accepting some storage adapter from the library user.

Allowed mentions

The allowed mention config for messages seems kind of weird as a component, as it doesn't show up in the actual message, but there's not really a better way to represent it, honestly. allowedMentionsComponent

Error handlers

Add onError callbacks to enable catching errors, for individual commands and globally on the gatekeeper instance

Command aliases

Add an aliases option for commands to register the same command for those extra names

Sub command support

I personally don't have a huge use case for this, but others might ¯\_(ツ)_/¯

JSX??

I've had some requests to use JSX for rendering replies... maybe that can work? Can only try and see ¯\_(ツ)_/¯

Make defer into an option on commands

Instead of context.defer(), define defer: true in the command options. This makes sense because a command can only be deferred once

Not sure about event handlers 🤔 ideas:

  • Another option deferComponents: true
  • Pass an option object to the handler option, e.g. onClick: { defer: true, callback: () => {} }

Support other types of slash command options

Namely:

  • User, which resolves to a DJS User
  • Channel, which resolves to a DJS Channel
  • Role, which resolves to a DJS Role
  • Mentionable, which resolves to User | GuildMember | Role,
    or maybe something easier to resolve, like { type: 'user', user: User } | { type: 'guildMember', member: GuildMember } | ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.