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 🙏

© 2026 – Pkg Stats / Ryan Hefner

disbord

v2.3.9

Published

bo-yakitarako専用のオレオレDiscord botフレームワーク

Readme

disbord

bo-yakitarako専用のオレオレDiscord botフレームワーク。プラグイン機構は持たず、気に入った機能は都度フレームワーク本体に直接組み込む方針(拡張性より一体性を優先)。

新規bot作成は create-disbord-app から始めてください。このREADMEはdisbordパッケージ自体(CLI・ランタイム)の使い方をまとめたものです。

インストール

create-disbord-appが生成するbotのpackage.jsonにはdisbordが依存として自動的に追加されます。手動で追加する場合は次の通りです。

bun add disbord

TypeScript v7系をpeerDependenciesとして要求します。

クイックスタート

bunx create-disbord-app my-bot
cd my-bot
bun run dev

bun run devdisbord dev)は起動時にslashCommandのREST登録・(DB有効時は)migrationを自動で行い、そのままbotを起動します。

disbord.config.ts

プロジェクトルートに1つだけ置く設定ファイルです。

import type { Config } from 'disbord';

export default {
  intents: ['Guilds', 'GuildMessages'],
  botErrorMessage: 'エラっちゃったサンプル',
} satisfies Config;
  • token / clientId / guildId / db.tursoDatabaseUrl / db.tursoAuthToken: 値そのもの(process.env.ALT_TOKENのような任意の環境変数を参照する式でもよい)を書く。未指定時はキー名をUPPER_SNAKE_CASEにしたデフォルトの環境変数名(clientIdCLIENT_ID)へ自動フォールバックする
  • guildId: 指定するとdisbord commands pushがguild単位登録(反映が即時)になる。未指定ならglobal登録(反映まで最大1時間)
  • coreClass / db: それぞれdisbord enable core-class / disbord enable dbで有効化する(後述)
  • botErrorMessage: BotErrormessage未指定のもの)がthrowされた際に返信する文言。固定文字列または(error: Error) => string
  • argsSplitter: customIdへ引数を埋め込む際の区切り文字のグローバル既定値(未指定時-

CLIコマンド

| コマンド | 説明 | | --- | --- | | disbord dev | 開発サーバーを起動する(bun --watchのラッパー。起動時にcommands push・(DB有効時)migrateを自動実行) | | disbord build | 本番デプロイ用にdist/main.jsdist/.envを生成する | | disbord commands push [--production] | slashCommandをDiscordへREST登録する | | disbord commands delete [--production] | 登録済みslashCommandを削除する | | disbord env [--production\|--all] | env/配下の環境変数を暗号化⇔復号にtoggleする | | disbord env encrypt [--production\|--all] | env/配下を暗号化する(固定) | | disbord env decrypt [--production\|--all] | env/配下を復号する(固定) | | disbord generate event <name> | src/events/<name>.tsのひな形を追加生成する | | disbord generate once <name> | src/once/<name>.tsのひな形を追加生成する | | disbord generate component <button\|selectMenu> | src/components/buttons.tsselectMenus.tsを追加生成する(未生成なら) | | disbord generate workflow ssh | .github/workflows/deploy.yamlを(再)生成する(SSH+systemd userサービスへのデプロイ用) | | disbord once <name> [--production] | src/once/<name>.tsをbotとして1回だけ起動して実行する | | disbord generate model <Name> | src/db/models/<Name>.tsにdecorator付きモデルクラスを追加生成する(DB有効時のみ) | | disbord migrate [--production] | モデル定義からschema.ts・migrationファイルを生成し、DBに適用する(DB有効時のみ) | | disbord model type | 各モデルファイル末尾のnamespace Data型ブロックだけを再生成する(schema.ts再生成・migration・DB接続はしない。DB有効時のみ) | | disbord studio | .disbord/db/dev.dbを対象にdrizzle studioサーバーを起動する(DB有効時のみ) | | disbord enable db / disbord enable core-class [ClassName] | 後からdb/coreClassを個別に有効化する | | disbord disable db / disbord disable core-class | 有効化したdb/coreClassを個別に無効化する(確認プロンプトあり) | | disbord --version, -v | バージョンを表示する | | disbord --help, -h / disbord help | コマンド一覧を表示する(DB有効時のみDB系コマンドも表示) |

本番実行はdisbord buildが生成したdist/main.jsbunで直接叩くだけで、disbord startのようなコマンドは存在しません。

components(src/components/

buttons.ts / selectMenus.ts / slashCommands.tsにそれぞれexport default { ... } satisfies XxxRegistrationの形でルーティングを宣言します。discord.jsのBuilderは直書きせず、素朴なオブジェクト(例: { label, style?, disabled?, args? })または(...args) => componentの関数で書きます。

slashCommands.tsだけは必須で、buttons.ts/selectMenus.tsは任意です。使う時だけdisbord generate component button / disbord generate component selectMenuで追加生成してください。

// src/components/buttons.ts
import type { ButtonRegistration } from 'disbord';

export default {
  ping: {
    component: { label: 'Ping' },
    execute: async (interaction) => {
      await interaction.reply('pong');
    },
  },
} satisfies ButtonRegistration;
  • executeの第1引数はdisbordが軽くラップしたInteraction(replyと同じシグネチャのephemeralメンバーを追加で持つ)
  • executeの第2引数はCoreクラスのインスタンス(coreClass.enable時)、それ以外は...args: string[](customIdに埋め込んだ引数の復元値)
  • argsSplitter?: stringをentryごとに指定でき、customIdの区切り文字を上書きできる
  • slashCommands.ts{ description?, options?, execute }のオブジェクト形に加え、execute関数を直接指定する形(例: ping: async (interaction) => {...})も書ける

makeButtonRow / makeSelectMenuRowdisbordから直接importして使い、ジェネリクスは書きません。

events(src/events/

1ファイル1イベント、ファイル名はdiscord.jsのイベント名(例: messageCreate.ts)。disbord generate event <name>で追加生成します。interactionCreate用のイベントファイルは存在しません(componentsのルーティングに統合済み)。

// src/events/messageCreate.ts
import type { Message } from 'disbord';

export default async function (message: Message) {
  if (message.author.bot) return;
};

once(src/once/

常駐せず1回だけ処理を実行して終了するbot用の入り口です。disbord generate once <name>src/once/<name>.tsを生成し、disbord once <name> [--production]で実行します(disbord builddist/<name>.jsとしても出力します。mainはbot本体のエントリdist/main.jsと衝突するため予約済みで使えません)。DB有効時はdb/Model、coreClass有効時はcoreStoreもそのままimportして使えます。

// src/once/notice.ts
import type { Client } from 'discord.js';

export default async function (client: Client<true>) {
  //
}

Core機構

複数のcomponentsで使い回す制御クラス(Core)を、guild/category/channel/user/globalいずれかの単位でインスタンス管理する仕組みです。disbord enable core-classで有効化するとsrc/{ClassName}.tsが生成されます。

import { coreStore } from 'disbord';

// 任意のタイミング(例: 開始用slashCommandのexecute内)でインスタンスを登録する
const core = coreStore.create(interaction);

instanceLevelに対応するキーがinteractionから解決できない場合(例: guild単位のCoreをDM上で使おうとした)はBotError(instanceInvalidMessage)がthrowされます。

DB層(src/db/models/

Drizzle + libSQL。モデルクラスを1つ書くだけでdisbord migrateschema.ts・migrationファイルを自動生成します。disbord enable dbで有効化します。

// src/db/models/Job.ts
import type { Dayjs } from 'dayjs';
import { Model, Table, Column, Relate } from 'disbord';
import { User } from './User';

@Table('jobs')
export class Job extends Model<Job.Data> {
  @Relate(() => User, { onDelete: 'cascade' })
  accessor userId!: string;

  @Column('text')
  accessor displayName!: string;

  @Column('integer', { mode: 'timestamp_ms' })
  accessor actAt!: Dayjs;
}

// AUTO-GENERATED by disbord. Do not edit below this line — regenerated by `disbord generate model` / `disbord migrate` / `disbord model type`.
export namespace Job {
  export type Data = { userId: string; displayName: string; actAt: Date | Dayjs };
}

id / createdAt / updatedAtは全モデル共通で自動付与されます。Model<Job.Data>が要求するnamespace Job { export type Data = ... }ブロックは手書き不要で、disbord generate model / disbord migrate / disbord model type実行のたびに@Column/@Relateのメタデータから機械的に導出してファイル末尾へ自動生成されます(timestamp_msのaccessorは読み取り時Dayjs固定ですが、Job.Data側は読み取ったDayjs値をそのまま渡し回せるようDate | Dayjsにします。Job.create()/find()/update()等の入力型はこのJob.Dataを経由するため、キー名のtypoやカラム追加漏れがコンパイルエラーで検知できます。defaultが指定されたカラムは?付きのoptionalになり、create()時に省略できます)。接続先はTurso用の環境変数の有無で自動判定され(未設定ならローカルsqlite.disbord/db/dev.db)、中身はdisbord studioで確認できます。

@Columndefaultオプションは値の種類でDB側/JS側どちらのdefaultになるか変わります。固定値(例: default: 'pending')はDBスキーマのDEFAULT句として、関数(例: default: () => crypto.randomUUID())はdrizzle-orm(JS側)がINSERT時に評価する値として扱われます(生SQLでのINSERTには効きません)。type/modeごとにdefaultの型も絞られており(例: mode: 'boolean'ならbooleanのみ)、mode: 'timestamp_ms'のカラムはDateではなくDayjs(固定値・() => Dayjs関数どちらも)で指定します(DBへ渡す際は内部でDateへ変換されます)。さらにmode: 'timestamp_ms'のカラムに限り特別な値default: 'now'も使え、DB側のDEFAULT (unixepoch('subsec') * 1000)(挿入時刻のミリ秒unix時間)になります。defaultが指定されたカラムは自動生成されるJob.Data側でも?付きのoptionalになるため、Job.create()呼び出し時にその値の指定を省略できます(省略した場合はDB/drizzle側のdefaultがそのまま使われます)。

デプロイ(.github/workflows/

disbord generate workflow ssh.github/workflows/deploy.yamlを生成します。pushをトリガーにビルド後、SSH経由でリモートホストへ配置し、systemd(--user)のサービスとして起動・再起動します。onceスクリプトがある場合はそれぞれtimerユニットも合わせてデプロイし、disbord.config.tstimerで指定したスケジュールで定期実行します(timerが未設定のonceスクリプトは手動実行専用とみなし、disbord.config.tsへの自動補完もdeploy.yamlへのデプロイ対象への追加も行いません)。lefthook.ymlがあればpre-commitにも再生成コマンドが追加され、config変更などがdeploy.yamlへ自動で反映されます。

エラーハンドリング

BotErrorがthrowされると大元のtry/catchでcatchされ、messageがあればそれを、無ければdisbord.config.tsbotErrorMessageを返信します。BotError以外のdiscord.js由来のエラーは素通しされます。

Lint / Format / テスト

bun run lint    # oxlint --fix + oxfmt --write
bun run test    # bun test
bunx tsc --noEmit

lint設定はdisbord/lintをextendsするoxlint.config.ts(TS製)。create-disbord-appが生成するlefthook.ymlにより、pre-commitでlint→fmt→env暗号化(--all)が自動実行されます。