@developer.krd/discord-dashboard 0.1.3 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,52 +2,73 @@
2
2
 
3
3
  An advanced, plug-and-play Discord dashboard package for bot developers.
4
4
 
5
- Build a fully functional, beautiful web dashboard for your bot without writing a single line of frontend code. Powered by Express, this package handles the OAuth2 login flow, session management, UI rendering, and API routing out of the box.
5
+ Build a full web dashboard for your bot without writing frontend code. The package provides built-in rendering, Discord OAuth2 flow, and adapters for Express, Elysia, and Fastify.
6
6
 
7
7
  ## ✨ Features
8
8
 
9
- - **No Frontend Coding:** Generates a beautiful React/Vue-like UI using pure server-side rendering.
10
- - **Built-in Auth:** Complete Discord OAuth2 login flow with secure session management.
11
- - **Guild Access Control:** Automatically filters guilds based on admin/manage server permissions.
12
- - **Fluent Designer API:** Build your dashboard cleanly using a chainable builder pattern.
13
- - **Custom CSS Injection:** Fully theme the dashboard to match your bot's branding.
14
- - **Extensible Plugins:** Create separate plugin panels with actionable buttons and forms.
15
- - **Rich Form Fields:** Support for text, selects, booleans, and drag-and-drop string lists.
16
- - **Smart Discord Lookups:** Website autocomplete fields for finding Roles, Channels, and Members.
17
- - **Discord-like UI:** Familiar server rail with avatars and invite-on-click for missing guilds.
9
+ - **No frontend app required:** Server-rendered dashboard UI with built-in client script.
10
+ - **Multiple adapters:** `createExpressAdapter`, `createElysiaAdapter`, `createFastifyAdapter`.
11
+ - **Discord OAuth2 flow:** Login, callback exchange, and session persistence.
12
+ - **Theming and layouts:** Built-in layouts/themes (`default`, `compact`, `shadcn-magic`) plus custom renderers.
13
+ - **Home & plugin builders:** Dynamic sections/panels with typed action handlers.
14
+ - **Discord helper API:** Role/channel/member fetch & search helpers inside action context.
15
+ - **TypeScript-first:** Strict typed options, context, fields, and plugin contracts.
16
+
17
+ ---
18
+
19
+ ## 🎨 Templates
20
+
21
+ Browse built-in templates and screenshot placeholders in [src/templates/templates.md](src/templates/templates.md).
18
22
 
19
23
  ---
20
24
 
21
25
  ## 📦 Installation
22
26
 
23
27
  ```bash
24
- npm install @developer.krd/discord-dashboard
28
+ npm install @developer.krd/discord-dashboard discord.js
25
29
  ```
26
30
 
27
- _(This package supports TypeScript, JavaScript, and ESM out of the box. Node.js >= 18 is required)._
31
+ Install only the server stack you use:
28
32
 
29
- ---
33
+ ```bash
34
+ # Express
35
+ npm install express express-session
36
+
37
+ # Elysia
38
+ npm install elysia
39
+
40
+ # Fastify
41
+ npm install fastify @fastify/cookie @fastify/session
42
+ ```
43
+
44
+ Node.js `>=18` is required.
30
45
 
31
- ## 🚀 Quick Start (Direct Configuration)
46
+ ---
32
47
 
33
- The fastest way to get your dashboard running is by instantiating the `DiscordDashboard` class directly.
48
+ ## 🚀 Quick Start (Express)
34
49
 
35
50
  ```ts
36
51
  import express from "express";
37
- import { DiscordDashboard } from "@developer.krd/discord-dashboard";
52
+ import { Client, GatewayIntentBits } from "discord.js";
53
+ import { createExpressAdapter } from "@developer.krd/discord-dashboard";
38
54
 
39
55
  const app = express();
56
+ const client = new Client({ intents: [GatewayIntentBits.Guilds] });
40
57
 
41
- const dashboard = new DiscordDashboard({
42
- app, // Attach to your existing Express app
58
+ createExpressAdapter({
59
+ app,
60
+ client,
43
61
  basePath: "/dashboard",
44
62
  dashboardName: "My Bot Control",
63
+
45
64
  botToken: process.env.DISCORD_BOT_TOKEN!,
46
65
  clientId: process.env.DISCORD_CLIENT_ID!,
47
66
  clientSecret: process.env.DISCORD_CLIENT_SECRET!,
48
67
  redirectUri: "http://localhost:3000/dashboard/callback",
49
68
  sessionSecret: process.env.DASHBOARD_SESSION_SECRET!,
50
- ownerIds: ["YOUR_DISCORD_USER_ID"],
69
+
70
+ uiTemplate: "shadcn-magic",
71
+ uiTheme: "shadcn-magic",
51
72
 
52
73
  getOverviewCards: async (context) => [
53
74
  {
@@ -55,7 +76,6 @@ const dashboard = new DiscordDashboard({
55
76
  title: "Bot Uptime",
56
77
  value: `${Math.floor(process.uptime() / 60)} min`,
57
78
  subtitle: `Logged in as ${context.user.username}`,
58
- intent: "success",
59
79
  },
60
80
  {
61
81
  id: "guilds",
@@ -70,10 +90,10 @@ const dashboard = new DiscordDashboard({
70
90
  {
71
91
  id: "welcome",
72
92
  title: "Welcome Settings",
93
+ categoryId: "general",
73
94
  description: context.selectedGuildId ? "Guild-specific setup" : "User-level setup",
74
95
  fields: [
75
96
  { id: "enabled", label: "Enable Welcome", type: "boolean", value: true },
76
- { id: "channel", label: "Channel", type: "channel-search" },
77
97
  { id: "message", label: "Message", type: "textarea", value: "Welcome to the server!" },
78
98
  ],
79
99
  actions: [{ id: "saveWelcome", label: "Save", variant: "primary" }],
@@ -89,131 +109,116 @@ const dashboard = new DiscordDashboard({
89
109
  },
90
110
  });
91
111
 
92
- // Start your Express server normally
112
+ await client.login(process.env.DISCORD_BOT_TOKEN!);
93
113
  app.listen(3000, () => {
94
114
  console.log("Dashboard live at: http://localhost:3000/dashboard");
95
115
  });
96
116
  ```
97
117
 
98
- ---
99
-
100
- ## 🎨 Fluent Dashboard Designer (Recommended)
101
-
102
- For larger bots, putting all your configuration in one object gets messy. Use the `DashboardDesigner` class to build your dashboard modularly.
103
-
104
- This approach also allows you to easily inject **Custom CSS** and define dashboard colors.
118
+ ## 🚀 Quick Start (Elysia)
105
119
 
106
120
  ```ts
107
- import express from "express";
108
- import { DashboardDesigner } from "@developer.krd/discord-dashboard";
121
+ import { Elysia } from "elysia";
122
+ import { Client, GatewayIntentBits } from "discord.js";
123
+ import { createElysiaAdapter } from "@developer.krd/discord-dashboard";
109
124
 
110
- const app = express();
125
+ const client = new Client({ intents: [GatewayIntentBits.Guilds] });
126
+ const app = new Elysia();
111
127
 
112
- const dashboard = new DashboardDesigner({
128
+ createElysiaAdapter({
113
129
  app,
130
+ client,
131
+ basePath: "/dashboard",
132
+ dashboardName: "My Bot Control",
133
+
114
134
  botToken: process.env.DISCORD_BOT_TOKEN!,
115
135
  clientId: process.env.DISCORD_CLIENT_ID!,
116
136
  clientSecret: process.env.DISCORD_CLIENT_SECRET!,
117
137
  redirectUri: "http://localhost:3000/dashboard/callback",
118
138
  sessionSecret: process.env.DASHBOARD_SESSION_SECRET!,
119
- })
120
- .setup({
121
- ownerIds: ["1234567890"],
122
- botInvitePermissions: "8",
123
- })
124
- // Customize the default color palette
125
- .setupDesign({
126
- primary: "#4f46e5",
127
- rail: "#181a20",
128
- panel: "#2f3136",
129
- })
130
- // Inject your own CSS rules
131
- .customCss(
132
- `
133
- .brand { font-size: 1.2rem; text-transform: uppercase; }
134
- button.primary { box-shadow: 0 4px 15px rgba(79, 70, 229, 0.4); }
135
- `,
136
- )
137
- // Build a Guild-specific settings category
138
- .guildCategory("pets", "Pets", (category) => {
139
- category.section({
140
- id: "pets-guild",
141
- title: "Guild Pets",
142
- fields: [{ id: "petsChannelId", label: "Pets Channel", type: "channel-search" }],
143
- actions: [{ id: "saveGuildPets", label: "Save", variant: "primary" }],
144
- });
145
- })
146
- // Handle the save action
147
- .onHomeAction("saveGuildPets", async (context, payload) => {
148
- const channelId = String(payload.values.petsChannelId ?? "");
149
- const channel = await context.helpers.getChannel(channelId);
150
- if (!channel) return { ok: false, message: "Channel not found" };
151
- return { ok: true, message: "Saved successfully!", refresh: true };
152
- })
153
- // Automatically instantiates the DiscordDashboard class
154
- .createDashboard();
155
-
156
- app.listen(3000, () => console.log("Dashboard ready!"));
139
+
140
+ uiTemplate: "shadcn-magic",
141
+ uiTheme: "shadcn-magic",
142
+ });
143
+
144
+ await client.login(process.env.DISCORD_BOT_TOKEN!);
145
+ app.listen({ port: 3000 });
146
+ console.log("Dashboard live at: http://localhost:3000/dashboard");
157
147
  ```
158
148
 
159
- ---
149
+ ## 🚀 Quick Start (Fastify)
160
150
 
161
- ## 🧩 Built-in Helper Functions
151
+ ```ts
152
+ import Fastify from "fastify";
153
+ import fastifyCookie from "@fastify/cookie";
154
+ import fastifySession from "@fastify/session";
155
+ import { Client, GatewayIntentBits } from "discord.js";
156
+ import { createFastifyAdapter } from "@developer.krd/discord-dashboard";
157
+
158
+ const fastify = Fastify({ logger: true });
159
+ const client = new Client({ intents: [GatewayIntentBits.Guilds] });
160
+
161
+ await fastify.register(fastifyCookie);
162
+ await fastify.register(fastifySession, {
163
+ secret: process.env.DASHBOARD_SESSION_SECRET!,
164
+ cookie: { secure: false },
165
+ });
166
+
167
+ createFastifyAdapter(fastify, {
168
+ client,
169
+ basePath: "/dashboard",
170
+ dashboardName: "My Bot Control",
162
171
 
163
- Whenever you handle an action (`onHomeAction` or inside a Plugin), you get access to the `context.helpers` object. These automatically use the bot token to fetch data from the Discord API.
172
+ botToken: process.env.DISCORD_BOT_TOKEN!,
173
+ clientId: process.env.DISCORD_CLIENT_ID!,
174
+ clientSecret: process.env.DISCORD_CLIENT_SECRET!,
175
+ redirectUri: "http://localhost:3000/dashboard/callback",
176
+ sessionSecret: process.env.DASHBOARD_SESSION_SECRET!,
164
177
 
165
- - `getChannel(channelId)`
166
- - `getGuildChannels(guildId)`
167
- - `getRole(guildId, roleId)`
168
- - `getGuildRoles(guildId)`
169
- - `getGuildMember(guildId, userId)`
170
- - `searchGuildRoles(guildId, query, options)`
171
- - `searchGuildChannels(guildId, query, options)`
178
+ uiTemplate: "shadcn-magic",
179
+ uiTheme: "shadcn-magic",
180
+ });
181
+
182
+ await client.login(process.env.DISCORD_BOT_TOKEN!);
183
+ await fastify.listen({ port: 3000, host: "0.0.0.0" });
184
+ console.log("Dashboard live at: http://localhost:3000/dashboard");
185
+ ```
172
186
 
173
187
  ---
174
188
 
175
- ## 🛠️ Plugin Scopes & Forms
189
+ ## 🔌 Adapter Notes
176
190
 
177
- Plugins are modular features you can attach to the dashboard. They can be restricted to specific scopes.
191
+ - **Express:** `createExpressAdapter(options)`
192
+ - **Elysia:** `createElysiaAdapter(options)`
193
+ - **Fastify:** `createFastifyAdapter(fastify, options)`
178
194
 
179
- - `scope: "user"` Shows only on the User Dashboard (when no server is selected).
180
- - `scope: "guild"` → Shows only on the Guild Dashboard.
181
- - `scope: "both"` → (Default) Shows everywhere.
195
+ For Fastify, you must register `@fastify/cookie` and `@fastify/session` before wiring the adapter, since dashboard routes read/write `request.session`.
182
196
 
183
- ### Example: Ticket Panel Builder Plugin
197
+ ---
184
198
 
185
- ```ts
186
- import { DiscordDashboard } from "@developer.krd/discord-dashboard";
199
+ ## 🛠️ Extensible Plugins
187
200
 
188
- const dashboard = new DiscordDashboard({
189
- // ... core credentials ...
201
+ ```ts
202
+ createExpressAdapter({
203
+ // ... core config ...
190
204
  plugins: [
191
205
  {
192
- id: "tickets",
193
- name: "Tickets",
194
- scope: "guild",
206
+ id: "runtime",
207
+ name: "System Runtime",
208
+ description: "Live bot diagnostics",
195
209
  getPanels: async () => [
196
210
  {
197
- id: "ticket-panel",
198
- title: "Ticket Panel Generator",
211
+ id: "runtime-status",
212
+ title: "Diagnostics",
199
213
  fields: [
200
- { id: "targetChannel", label: "Target Channel", type: "channel-search", editable: true },
201
- { id: "title", label: "Embed Title", type: "text", editable: true, value: "Need help?" },
202
- { id: "description", label: "Embed Description", type: "textarea", editable: true },
203
- { id: "buttonLabel", label: "Button Label", type: "text", editable: true, value: "Open Ticket" },
214
+ { label: "Logged in as", value: client.user?.tag ?? "Unknown" },
215
+ { label: "Uptime", value: `${Math.floor(process.uptime())}s` },
204
216
  ],
205
- actions: [{ id: "publishTicket", label: "Publish to Channel", variant: "primary", collectFields: true }],
217
+ actions: [{ id: "refreshRuntime", label: "Refresh", variant: "primary", collectFields: false }],
206
218
  },
207
219
  ],
208
220
  actions: {
209
- publishTicket: async (context, body) => {
210
- // body.values contains the form data because collectFields was true
211
- const data = body as { values?: Record<string, unknown> };
212
- const values = data.values ?? {};
213
-
214
- console.log(`Creating ticket panel in ${values.targetChannel}`);
215
- return { ok: true, message: `Ticket panel published!`, data: values };
216
- },
221
+ refreshRuntime: async () => ({ ok: true, message: "Data refreshed", refresh: true }),
217
222
  },
218
223
  },
219
224
  ],
@@ -222,15 +227,26 @@ const dashboard = new DiscordDashboard({
222
227
 
223
228
  ---
224
229
 
225
- ## 🔍 Lookup Fields (Discord Entities)
230
+ ## 🧩 Built-in Helper Functions
226
231
 
227
- Instead of forcing users to copy/paste IDs, use lookup fields to provide a rich website autocomplete experience.
232
+ Inside `home.actions` and `plugins.actions`, use `context.helpers`:
228
233
 
229
- - `type: "role-search"`: Type a role name, select it, and the action receives the full Role object.
230
- - `type: "channel-search"`: Type a channel name.
231
- - `type: "member-search"`: Type a username or nickname.
234
+ - `getGuildIconUrl(guildId, iconHash)`
235
+ - `getUserAvatarUrl(userId, avatarHash)`
236
+ - `getChannel(channelId)`
237
+ - `getGuildChannels(guildId)`
238
+ - `searchGuildChannels(guildId, query, options?)`
239
+ - `getRole(guildId, roleId)`
240
+ - `getGuildRoles(guildId)`
241
+ - `searchGuildRoles(guildId, query, options?)`
242
+ - `searchGuildMembers(guildId, query, options?)`
243
+ - `getGuildMember(guildId, userId)`
244
+
245
+ ---
232
246
 
233
- You can configure lookups with filters:
247
+ ## 🔍 Lookup Fields
248
+
249
+ Field types include `role-search`, `channel-search`, and `member-search`, and you can provide lookup options in field config (for limits and filters).
234
250
 
235
251
  ```ts
236
252
  {
@@ -239,8 +255,8 @@ You can configure lookups with filters:
239
255
  type: "channel-search",
240
256
  lookup: {
241
257
  limit: 5,
242
- channelTypes: [0, 5] // 0 = GUILD_TEXT, 5 = GUILD_ANNOUNCEMENT
243
- }
258
+ channelTypes: [0, 5],
259
+ },
244
260
  }
245
261
  ```
246
262
 
@@ -248,35 +264,28 @@ You can configure lookups with filters:
248
264
 
249
265
  ## 📚 API Reference
250
266
 
251
- ### `DashboardDesigner` Methods
267
+ `DashboardOptions` includes:
252
268
 
253
- - **`setup(options)`**: Set core info (`ownerIds`, `dashboardName`, `basePath`, `uiTemplate`).
254
- - **`setupDesign(config)`**: Override theme colors (e.g., `primary`, `bg`, `panel`).
255
- - **`customCss(cssString)`**: Inject raw CSS to completely customize the dashboard.
256
- - **`setupCategory(id, label, build)`**: Add tabs to the one-time setup view.
257
- - **`userCategory(id, label, build)`**: Add tabs to the user dashboard.
258
- - **`guildCategory(id, label, build)`**: Add tabs to the server dashboard.
259
- - **`onHomeAction(actionId, handler)`**: Define what happens when a button is clicked.
260
- - **`createDashboard()`**: Terminal method. Builds the config and returns a `DiscordDashboard` instance.
269
+ - OAuth/session config (`clientId`, `clientSecret`, `redirectUri`, `sessionSecret`, ...)
270
+ - Dashboard presentation (`dashboardName`, `basePath`, `uiTemplate`, `uiTheme`, `setupDesign`)
271
+ - Dynamic content (`getOverviewCards`, `home`, `plugins`)
272
+ - Runtime dependencies (`client`, optional framework app where supported)
261
273
 
262
- ### `DiscordDashboard` Methods
274
+ Also exported:
263
275
 
264
- - **`app`**: The Express instance (either the one you provided, or a newly created one).
265
- - **`start()`**: Starts the internal HTTP server (only if you didn't pass your own Express app).
266
- - **`stop()`**: Gracefully shuts down the internal server.
276
+ - `DashboardEngine`
277
+ - `DashboardDesigner`
267
278
 
268
279
  ---
269
280
 
270
281
  ## 🔒 Required Discord OAuth2 Setup
271
282
 
272
- To make login work:
273
-
274
283
  1. Go to the [Discord Developer Portal](https://discord.com/developers/applications).
275
- 2. Open your Application -> **OAuth2**.
276
- 3. Add your Redirect URI (e.g., `http://localhost:3000/dashboard/callback`).
277
- 4. Grab your `CLIENT_ID` and `CLIENT_SECRET` to use in your dashboard config.
284
+ 2. Open your Application **OAuth2**.
285
+ 3. Add your redirect URI (example: `http://localhost:3000/dashboard/callback`).
286
+ 4. Use your `CLIENT_ID` and `CLIENT_SECRET` in dashboard config.
278
287
 
279
- _Note: Ensure your `sessionSecret` is a long, random string in production, and run your bot behind HTTPS._
288
+ Use a strong `sessionSecret` in production and serve behind HTTPS.
280
289
 
281
290
  ---
282
291