0.2.1 • Published 1 year ago

@femshima/djs-interaction v0.2.1

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

djs-interaction

discord.jsのコマンドやComponentの定義と Interactionのハンドラを近い位置に書けるようにするフレームワークです。

使い方

詳しい使い方はsample/を見てください。

Interactionの種類説明
Commandスラッシュコマンド
SubCommandGroupスラッシュコマンド関連、ApplicationCommandSubGroupDataに相当
SubCommandスラッシュコマンド関連、ApplicationCommandSubCommandDataに相当
MessageContextMenuメッセージを右クリックすると出てくるコンテキストメニュー
UserContextMenuユーザーを右クリックすると出てくるコンテキストメニュー
Buttonボタン
SelectMenu選択ボックス
Modalモーダルウィンドウ

Setup

djs-interactionのCommandSubCommandGroupSubCommandMessageContextMenuUserContextMenuButtonSelectMenuModalを継承したクラスを一つでもインスタンス化する前にframe.setup()を呼び出す必要があります。 また、frame.setup()を複数回呼び出すとその都度コマンドの登録が行われるため、問題が発生する可能性があります。

import { frame } from 'djs-interaction';
//...
await frame.setup({
  client,
  commands: {
    ...Command,
    ...ContextMenu,
  },
  components: Component,
  guilds: !env.production,
  subscribeToEvent: true,
  async fallback(interaction) {
    if ('replied' in interaction && !interaction.replied) {
      await interaction.reply('Unknown interaction.');
    }
  },
});

frame.setup()の引数は一つで、次のようなオブジェクトです。

キー説明
clientDiscord.jsのclientです。
commands登録するコマンド(CommandMessageContextMenuUserContextMenuを継承したもの)をすべてここに指定します。コマンドのクラス(インスタンス化してあっても、する前のものでも構いません)の配列または、keyを文字列、それらのクラスをvalueとするオブジェクトを渡してください。
components使用時に都度インスタンス化して使うもの(ButtonSelectMenuModalを継承したもの)をすべてここに指定します。コマンドのクラス(インスタンス化する前のものである必要があります)の配列または、keyを文字列、それらのクラスをvalueとするオブジェクトを渡してください。
subscribeToEventsetupメソッドの中で自動的にinteractionCreateイベントにハンドラを登録するかどうかbooleanで指定します。falseをセットした場合、別の場所でframe.interactionCreateをハンドラとして登録する必要があります。
fallback受信したinteractionのハンドラが見つからなかった場合や、ハンドラが応答しなかった場合に呼び出される関数です。
databaseデータベースとの連携を使用する場合、このオプションを使います。詳しくはデータベースと連携させるを参照してください。
idGenidを生成するクラスのインスタンスを指定します。ユニークなID(文字列)を生成して返すgenerateIDメソッドを実装している必要があります。

スラッシュコマンド(ChatInputApplicationCommand)

すべてのコマンド定義はCommandを継承している必要があります。 constructorでコマンド定義をsuperに渡して呼び出します。 handlerを実装していなくてもTypeScriptのエラーは出ませんが、interactionに応答しないとDiscord側でエラーメッセージが表示されるため、SubCommandを使用する時以外は実装することが推奨されます。

import { CommandInteraction } from 'discord.js';
import { Command } from 'djs-interaction';

export default class Ping extends Command {
  constructor() {
    super({
      name: 'ping',
      description: 'Ping!',
    });
  }

  async handle(interaction: CommandInteraction<'cached'>) {
    await interaction.reply({ content: 'Pong!' });
  }
}

サブコマンド

djs-interactionはサブコマンドにも対応しています。 サブコマンドではSubCommandを継承してください。 通常のコマンドと同じように、constructorでコマンド定義をsuperに渡して呼び出します。 ただし、通常のコマンドと異なり、handlerを定義しないとTypeScriptでエラーになります。

import { ChatInputCommandInteraction } from 'discord.js';
import { SubCommand } from 'djs-interaction';

export default class Locale extends SubCommand {
  constructor() {
    super({
      name: 'locale',
      description: 'shows supported locales',
    });
  }
  async handle(interaction: ChatInputCommandInteraction<'cached'>) {
    await interaction.reply('en,ja');
  }
}

サブコマンドを定義したら、それらをオプションとしてまとめたコマンドを定義します。

import { Command } from 'djs-interaction';
import Admin from './admin';
import Langs from './langs';
import Locale from './locales';

export default class Greet extends Command {
  constructor() {
    super({
      name: 'greet',
      description: 'Commands about greetings',
      options: [new Langs(), new Locale(), new Admin()],
    });
  }
}

なお、サブコマンドをもつコマンドでも、通常のコマンド同様handlerを定義することができます。handlerはCommand、(存在する場合は)SubCommandGroupSubCommandの順に呼び出されます。

handler内でdjs-interactionからインポートしたAbortErrorをthrowすると、そのhandler以降のhandlerは実行されません。すなわち、CommandのhandlerでAbortErrorをthrowすると、SubCommandGroupSubCommandのhandlerは実行されません。

//...
async handle(interaction: ChatInputCommandInteraction<'cached'>) {
  if (
    !interaction.member.permissions.has(PermissionFlagsBits.Administrator)
  ) {
    await interaction.reply(
      'You are not admin, so you cannot use this command.'
    );
    throw new AbortError();
  }
}
//...

サブコマンドグループ

サブコマンドをまとめるコマンドと同様に使います。ただし、CommandではなくSubCommandGroupを継承してください。

ContextMenu

ContextMenuには、ユーザーを右クリックしたときに実行されるUserApplicationCommandとメッセージを右クリックしたときに実行されるMessageApplicationCommandがあります。

基本的にはコマンド定義と同様ですが、UserApplicationCommandUserContextMenuを、MessageApplicationCommandMessageContextMenuを継承したクラスを作成してください。

Component

ここで、ComponentButtonSelectMenuModalのことを指しています(Modalは微妙かもしれませんが)。

これらもコマンド同様、定義をconstructor内でsuperに渡すだけです。

Buttonはhandlerを定義しなくてもエラーにはなりませんが、これはstyleがLinkのときにhandlerを定義しなくてもいいためです。そうでない場合は定義すべきです。

データベースと連携させる

デフォルトではInteractionの定義はメモリに保存されるため、プログラムを終了させた時点で蒸発します。これを防ぐには、データベースなどに保存しておく必要があります。

djs-interactionでデータベースを使うには、frame.setupの実行時にdatabaseオプションを指定します。

Prismaを使う場合

まず、スキーマの例を示します。重要なのはmodel Interactionの部分だけですので、他の部分は適宜変更してください。また、列名と型が同じであればテーブル名を変えても構いません。

generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Interaction {
  id           String  @id
  classKey     String
  classVersion String?
  data         Json
}

setup部分は次のように書きます。テーブル名はスキーマに合わせてください。

const prisma = new PrismaClient()
await frame.setup({
  //...
  database: prisma.interaction
});

Prismaを使わない場合

await frame.setup({
    //...
    database: {
      findUnique(options) {
        // options.where.idがidに一致するレコードを探して返します。
        // レコードの形式は次のようになっています。
        // {
        //   id: string; // depends on what kind of idgen you use.
        //   classKey: string; // the key set in class or the name of the class
        //   classVersion: string | null; // version set in class or null
        //   data: JsonObject;
        // }
        //
        // 例:
        // {
        //   id: 'id-1',
        //   classKey: 'Target',
        //   classVersion: null,
        //   data: {
        //     type: 'MODAL',
        //     message: 'msg',
        //     data: { d: 'X' },
        //   },
        // }
      },
      create(options) {
        // findUniqueで説明したようなレコードがoptions.dataとして渡されるので、データベースに登録します。
        // idが重複することは想定されていませんので、重複した場合は例外を投げるべきです。
      }
    }
  });
0.2.1

1 year ago

0.2.0

2 years ago

0.1.4

2 years ago

0.1.3

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago