djs-next 0.0.1 → 1.0.0-dev.2

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.

Potentially problematic release.


This version of djs-next might be problematic. Click here for more details.

@@ -1,4 +1,4 @@
1
- import { Message, EmbedBuilder, version as djsVersion } from 'discord.js';
1
+ import { Message, EmbedBuilder } from 'discord.js';
2
2
  import { exec } from 'child_process';
3
3
  import util from 'util';
4
4
  import os from 'os';
@@ -11,88 +11,30 @@ import { loadLocales } from '../utils/i18n.js';
11
11
 
12
12
  const execAsync = util.promisify(exec);
13
13
 
14
- export function buildDisplayMessage(content: string, color = 0x525AF1) {
15
- const djs = require('discord.js');
16
- const container = new djs.ContainerBuilder()
17
- .setAccentColor(color)
18
- .addTextDisplayComponents(
19
- new djs.TextDisplayBuilder().setContent(content)
20
- );
21
- return { components: [container], flags: 32768 };
22
- }
23
-
24
- export async function handleDNXT(message: Message, client: Client, devPrefix: 'dnxt' | 'nxt'): Promise<void> {
14
+ export async function handleDNXT(message: Message, client: DJSNextClient, prefix: 'dnxt' | 'nxt' = 'dnxt') {
25
15
  if (message.author.bot) return;
26
- if (!(client as any)._developers.includes(message.author.id)) return;
27
- if ((client as any).config?.devGuildId && message.guildId !== (client as any).config.devGuildId) return;
28
-
29
- const originalReply = message.reply.bind(message);
30
- message.reply = (async (content: any) => {
31
- if (typeof content === 'string') {
32
- return await originalReply({ ...buildDisplayMessage(content), allowedMentions: { repliedUser: false } });
33
- }
34
- if (!content.allowedMentions) content.allowedMentions = { repliedUser: false };
35
- return await originalReply(content);
36
- }) as any;
37
-
38
- const content = message.content.trim();
39
-
40
- // Build a list of valid dev command triggers: e.g. "dnxt", "!dnxt", "?dnxt", "nxt", "!nxt", etc.
41
- const validTriggers = [devPrefix];
42
- const clientPrefixes = (client as any)._prefixes || [];
43
- for (const p of clientPrefixes) {
44
- if (p !== '') validTriggers.push(`${p}${devPrefix}`);
45
- }
16
+ // Make sure only developers can use this
17
+ if (!client['_developers'].includes(message.author.id)) return;
46
18
 
47
- let matchedTrigger = validTriggers.find(t => content === t || content.startsWith(`${t} `));
48
- if (!matchedTrigger) return;
19
+ if (!message.content.startsWith(prefix)) return;
49
20
 
50
- const args = content.slice(matchedTrigger.length).trim().split(/ +/g);
21
+ const args = message.content.slice(prefix.length).trim().split(/ +/);
51
22
  const command = args.shift()?.toLowerCase();
52
23
 
53
- if (command === 'help') {
54
- const djs = require('discord.js');
55
-
56
- const container = new djs.ContainerBuilder()
57
- .setAccentColor(0x525AF1)
58
- .addTextDisplayComponents(
59
- new djs.TextDisplayBuilder().setContent(`# 📖 DNXT Toolkit Reference\n> Current prefix trigger: \`${matchedTrigger}\``)
60
- )
61
- .addSeparatorComponents(new djs.SeparatorBuilder())
62
- .addTextDisplayComponents(
63
- new djs.TextDisplayBuilder().setContent(`### 📊 Core Framework\n- \`${matchedTrigger}\` — Developer system dashboard\n- \`${matchedTrigger} help\` — Shows this reference menu`),
64
- new djs.TextDisplayBuilder().setContent(`### 💻 Execution & Diagnostics\n- \`${matchedTrigger} js <code>\` — Evaluates raw JS code\n- \`${matchedTrigger} sh <cmd>\` — Runs terminal shell script\n- \`${matchedTrigger} debug <code>\` — Evaluates JS with precise memory deltas`),
65
- new djs.TextDisplayBuilder().setContent(`### 📂 File System & Network\n- \`${matchedTrigger} cat <file>\` — Reads file contents\n- \`${matchedTrigger} curl <url>\` — Fetches remote URL data\n- \`${matchedTrigger} git <cmd>\` — Executes git repository commands`),
66
- new djs.TextDisplayBuilder().setContent(`### 🧰 Utilities\n- \`${matchedTrigger} <load|unload|reload> <target>\` — Manages system modules\n- \`${matchedTrigger} sync\` — Forces global slash command sync\n- \`${matchedTrigger} in <channel> <cmd>\` — Executes command in target channel\n- \`${matchedTrigger} restart\` — Restarts the bot completely\n- \`${matchedTrigger} shutdown\` — Stops the bot completely`)
67
- );
68
-
69
- await message.reply({ components: [container], flags: 32768, allowedMentions: { repliedUser: false } });
70
- return;
71
- }
72
-
73
24
  // Root dnxt command (Stats)
74
25
  if (!command) {
75
26
  const mem = process.memoryUsage();
27
+ const discordJsVersion = require('discord.js/package.json').version;
76
28
  const botPing = client.ws.ping;
77
- const djs = require('discord.js');
78
29
 
79
- const container = new djs.ContainerBuilder()
80
- .setAccentColor(0x525AF1)
81
- .addTextDisplayComponents(
82
- new djs.TextDisplayBuilder().setContent(`# 🛠️ Developer System Dashboard\n> **DNXT Framework Engine**`)
83
- )
84
- .addSeparatorComponents(new djs.SeparatorBuilder())
85
- .addTextDisplayComponents(
86
- new djs.TextDisplayBuilder().setContent(`### 📡 Network Status\n- **System Uptime:** <t:${Math.floor((Date.now() - client.uptime!) / 1000)}:R>\n- **WebSocket Latency:** \`${botPing}ms\``),
87
- new djs.TextDisplayBuilder().setContent(`### 📦 Host Environment\n- **Discord.js Library:** \`v${djsVersion}\`\n- **Node.js Runtime:** \`${process.version}\`\n- **Operating System:** \`${os.type()}\` (\`${os.cpus().length}\` thread cores, \`${(os.uptime() / 60 / 60).toFixed(2)}\` hrs uptime)`),
88
- new djs.TextDisplayBuilder().setContent(`### 🧠 Resource Utilization\n- **Physical Memory:** \`${(mem.rss / 1024 / 1024).toFixed(2)} MB\`\n- **Heap Allocated:** \`${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB\``)
89
- );
90
-
91
- await message.reply({
92
- components: [container],
93
- flags: 32768, // MessageFlags.IsComponentsV2
94
- allowedMentions: { repliedUser: false }
95
- });
30
+ const text =
31
+ `Module was loaded <t:${Math.floor((Date.now() - client.uptime!) / 1000)}:R>.\n` +
32
+ `DNXT framework plugin, discord.js \`${discordJsVersion}\`, \`Node.js ${process.version}\` on \`${os.type()}\`.\n` +
33
+ `Latencies: \`${botPing}ms\` websocket ping.\n` +
34
+ `Memory: \`${(mem.rss / 1024 / 1024).toFixed(2)} MB\` physical, \`${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB\` heap.\n` +
35
+ `System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2)}\` hrs system uptime.`;
36
+
37
+ await message.reply(text);
96
38
  return;
97
39
  }
98
40
 
@@ -113,11 +55,11 @@ export async function handleDNXT(message: Message, client: Client, devPrefix: 'd
113
55
  const end = process.hrtime.bigint();
114
56
  const timeMs = Number(end - start) / 1e6;
115
57
 
116
- if (typeof evaled !== 'string') evaled = util.inspect(evaled, { depth: 1, colors: true });
58
+ if (typeof evaled !== 'string') evaled = util.inspect(evaled, { depth: 1 });
117
59
 
118
- await sendPaginatedText(message, `✅ **Evaluated in ${timeMs.toFixed(3)}ms**\n`, evaled, 'ansi');
60
+ await sendPaginatedText(message, `✅ **Evaluated in ${timeMs.toFixed(3)}ms**\n`, evaled, 'js');
119
61
  } catch (err: any) {
120
- await sendPaginatedText(message, `❌ **Evaluation Error**\n`, err.message, 'ansi');
62
+ await sendPaginatedText(message, `❌ **Evaluation Error**\n`, err.message, 'js');
121
63
  }
122
64
  return;
123
65
  }
@@ -129,72 +71,53 @@ export async function handleDNXT(message: Message, client: Client, devPrefix: 'd
129
71
 
130
72
  try {
131
73
  const start = process.hrtime.bigint();
132
- let stdout = '', stderr = '', code = 0;
133
- try {
134
- const result = await execAsync(cmd);
135
- stdout = result.stdout;
136
- stderr = result.stderr;
137
- } catch (err: any) {
138
- stdout = err.stdout || '';
139
- stderr = err.stderr || err.message || '';
140
- code = err.code || 1;
141
- }
74
+ const { stdout, stderr } = await execAsync(cmd);
142
75
  const end = process.hrtime.bigint();
143
76
  const timeMs = Number(end - start) / 1e6;
144
77
 
145
- let resultText = `$ ${cmd}\n`;
146
- if (stdout) resultText += `${stdout}\n`;
147
- if (stderr) resultText += `${stderr}\n`;
148
- resultText += `\n[status] Return code ${code}`;
149
-
150
- await sendPaginatedText(message, `✅ **Executed in ${timeMs.toFixed(3)}ms**\n`, resultText, 'ansi');
78
+ const result = stdout || stderr || 'No output.';
79
+ await sendPaginatedText(message, `✅ **Executed in ${timeMs.toFixed(3)}ms**\n`, result, 'sh');
151
80
  } catch (err: any) {
152
- await sendPaginatedText(message, `❌ **Shell Error**\n`, err.message, 'ansi');
81
+ await sendPaginatedText(message, `❌ **Shell Error**\n`, err.message, 'sh');
153
82
  }
154
83
  return;
155
84
  }
156
85
 
157
86
  // Load / Unload / Reload
158
- if (command === 'load' || command === 'unload' || command === 'reload') {
87
+ if (command === 'reload' || command === 'load') {
159
88
  const target = args[0]?.toLowerCase();
160
89
  try {
161
90
  if (target === 'commands' && client['_commandsDir']) {
162
- if (command === 'unload' || command === 'reload') client.commands.clear();
163
- if (command === 'load' || command === 'reload') client.commands = await loadAndDeployCommands(client['_commandsDir'], client.token!, client['_clientId']!, client['_guildId']);
164
- await message.reply(`✅ Successfully ${command}ed commands.`);
91
+ client.commands.clear();
92
+ client.commands = await loadAndDeployCommands(client['_commandsDir'], client.token!, client['_clientId']!, client['_guildId']);
93
+ await message.reply('✅ Reloaded commands.');
165
94
  } else if (target === 'events' && client['_eventsDir']) {
166
- if (command === 'unload' || command === 'reload') {
167
- client.removeAllListeners();
168
- client['attachCoreListeners']();
169
- }
170
- if (command === 'load' || command === 'reload') await loadEvents(client, client['_eventsDir']);
171
- await message.reply(`✅ Successfully ${command}ed events.`);
95
+ client.removeAllListeners();
96
+ client['attachCoreListeners']();
97
+ await loadEvents(client, client['_eventsDir']);
98
+ await message.reply('✅ Reloaded events.');
172
99
  } else if (target === 'components' && client['_componentsDir']) {
173
- if (command === 'unload' || command === 'reload') client.components.clear();
174
- if (command === 'load' || command === 'reload') client.components = await loadComponents(client['_componentsDir']);
175
- await message.reply(`✅ Successfully ${command}ed components.`);
100
+ client.components.clear();
101
+ client.components = await loadComponents(client['_componentsDir']);
102
+ await message.reply('✅ Reloaded components.');
176
103
  } else if (target === 'locales' && client['_localesDir']) {
177
- if (command === 'load' || command === 'reload') loadLocales(client['_localesDir'], client.config.defaultLocale);
178
- await message.reply(`✅ Successfully ${command}ed locales.`);
104
+ loadLocales(client['_localesDir'], client.config.defaultLocale);
105
+ await message.reply('✅ Reloaded locales.');
179
106
  } else if (target === 'all' || !target) {
180
- if (command === 'unload' || command === 'reload') {
181
- client.removeAllListeners();
182
- client['attachCoreListeners']();
183
- client.commands.clear();
184
- client.components.clear();
185
- }
186
- if (command === 'load' || command === 'reload') {
187
- if (client['_eventsDir']) await loadEvents(client, client['_eventsDir']);
188
- if (client['_componentsDir']) client.components = await loadComponents(client['_componentsDir']);
189
- if (client['_localesDir']) loadLocales(client['_localesDir'], client.config.defaultLocale);
190
- if (client['_commandsDir']) client.commands = await loadAndDeployCommands(client['_commandsDir'], client.token!, client['_clientId']!, client['_guildId']);
191
- }
192
- await message.reply(`✅ Successfully ${command}ed all framework modules.`);
107
+ client.removeAllListeners();
108
+ client['attachCoreListeners']();
109
+ client.commands.clear();
110
+ client.components.clear();
111
+ if (client['_eventsDir']) await loadEvents(client, client['_eventsDir']);
112
+ if (client['_componentsDir']) client.components = await loadComponents(client['_componentsDir']);
113
+ if (client['_localesDir']) loadLocales(client['_localesDir'], client.config.defaultLocale);
114
+ if (client['_commandsDir']) client.commands = await loadAndDeployCommands(client['_commandsDir'], client.token!, client['_clientId']!, client['_guildId']);
115
+ await message.reply(' Reloaded all framework modules.');
193
116
  } else {
194
117
  await message.reply('❌ Unknown target. Valid targets: `commands, events, components, locales, all`');
195
118
  }
196
119
  } catch (err: any) {
197
- await message.reply(`❌ **${command.toUpperCase()} Error:** ${err.message}`);
120
+ await message.reply(`❌ **Reload Error:** ${err.message}`);
198
121
  }
199
122
  return;
200
123
  }
@@ -215,9 +138,48 @@ export async function handleDNXT(message: Message, client: Client, devPrefix: 'd
215
138
  return;
216
139
  }
217
140
 
141
+ // Sudo (Invoke command as another user)
142
+ if (command === 'su' || command === 'sudo') {
143
+ const targetUserId = args.shift();
144
+ const cmd = args.join(' ');
145
+ if (!targetUserId || !cmd) return void await message.reply(`❌ Usage: ${prefix} su <user_id> <command>`);
146
+
147
+ try {
148
+ const targetUser = await client.users.fetch(targetUserId.replace(/<@!?|>/g, ''));
149
+ if (!targetUser) throw new Error('User not found.');
150
+
151
+ // Create a mock message
152
+ const mockMessage = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
153
+ mockMessage.author = targetUser;
154
+ if (message.guild) {
155
+ mockMessage.member = await message.guild.members.fetch(targetUser.id).catch(() => null);
156
+ }
157
+ mockMessage.content = cmd;
158
+
159
+ client.emit('messageCreate', mockMessage as Message);
160
+ await message.reply(`✅ Invoked \`${cmd}\` as **${targetUser.tag}**.`);
161
+ } catch (e: any) {
162
+ await message.reply(`❌ **Sudo Error:** ${e.message}`);
163
+ }
164
+ return;
165
+ }
218
166
 
219
-
220
-
167
+ // Source Command (dnxt source <command>)
168
+ if (command === 'source' || command === 'src') {
169
+ const target = args.join(' ');
170
+ if (!target) return void await message.reply('❌ Please provide a command name.');
171
+ const cmdData = client.commands.get(target);
172
+ if (!cmdData || !cmdData.filepath) return void await message.reply('❌ Command not found or has no associated filepath.');
173
+
174
+ try {
175
+ const fs = await import('fs');
176
+ const content = fs.readFileSync(cmdData.filepath, 'utf8');
177
+ await sendPaginatedText(message, `📄 **Source of \`${target}\`**\n`, content, cmdData.filepath.split('.').pop() || '');
178
+ } catch (e: any) {
179
+ await message.reply(`❌ **Error reading source:** ${e.message}`);
180
+ }
181
+ return;
182
+ }
221
183
 
222
184
  // Curl (dnxt curl <url>)
223
185
  if (command === 'curl') {
@@ -255,11 +217,11 @@ export async function handleDNXT(message: Message, client: Client, devPrefix: 'd
255
217
  const timeMs = Number(end - start) / 1e6;
256
218
  const memDiff = (endMem - startMem) / 1024 / 1024;
257
219
 
258
- if (typeof evaled !== 'string') evaled = util.inspect(evaled, { depth: 1, colors: true });
220
+ if (typeof evaled !== 'string') evaled = util.inspect(evaled, { depth: 1 });
259
221
 
260
- await sendPaginatedText(message, `⏱️ **Debug Execution**\nTime: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`\n`, evaled, 'ansi');
222
+ await sendPaginatedText(message, `⏱️ **Debug Execution**\nTime: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`\n`, evaled, 'js');
261
223
  } catch (err: any) {
262
- await sendPaginatedText(message, `❌ **Debug Error**\n`, err.message, 'ansi');
224
+ await sendPaginatedText(message, `❌ **Debug Error**\n`, err.message, 'js');
263
225
  }
264
226
  return;
265
227
  }
@@ -268,27 +230,59 @@ export async function handleDNXT(message: Message, client: Client, devPrefix: 'd
268
230
  if (command === 'in') {
269
231
  const channelId = args.shift()?.replace(/<#|>/g, '');
270
232
  const cmd = args.join(' ');
271
- if (!channelId || !cmd) return void await message.reply(`❌ Usage: ${matchedTrigger} in <#channel|id> <command>`);
233
+ if (!channelId || !cmd) return void await message.reply(`❌ Usage: ${prefix} in <channel> <command>`);
272
234
  try {
273
235
  const targetChannel = await client.channels.fetch(channelId);
274
236
  if (!targetChannel || !targetChannel.isTextBased()) throw new Error('Invalid Text Channel.');
275
237
 
276
238
  const mockMessage = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
277
- Object.defineProperty(mockMessage, 'client', { value: client, configurable: true });
278
- if (message.guild) {
279
- Object.defineProperty(mockMessage, 'guild', { value: message.guild, configurable: true });
280
- Object.defineProperty(mockMessage, 'guildId', { value: message.guildId, configurable: true });
281
- }
282
- Object.defineProperty(mockMessage, 'channel', { value: targetChannel, configurable: true });
283
- Object.defineProperty(mockMessage, 'channelId', { value: targetChannel.id, configurable: true });
284
- Object.defineProperty(mockMessage, 'content', { value: cmd, configurable: true });
239
+ mockMessage.channel = targetChannel;
240
+ mockMessage.channelId = targetChannel.id;
241
+ mockMessage.content = cmd;
242
+
285
243
  client.emit('messageCreate', mockMessage as Message);
244
+ await message.reply(`✅ Redirected execution to <#${targetChannel.id}>.`);
286
245
  } catch (e: any) {
287
246
  await message.reply(`❌ **In Error:** ${e.message}`);
288
247
  }
289
248
  return;
290
249
  }
291
250
 
251
+ // Tasks Command (dnxt tasks)
252
+ if (command === 'tasks') {
253
+ const tasks = (client as any)._activeTasks as Map<string, NodeJS.Timeout>;
254
+ if (!tasks || tasks.size === 0) return void await message.reply('No active background tasks running.');
255
+
256
+ let text = `⚙️ **Active Background Tasks (${tasks.size})**\n`;
257
+ for (const [name] of tasks.entries()) {
258
+ text += `- \`${name.split('/').pop()}\`\n`;
259
+ }
260
+ await sendPaginatedText(message, '', text, '');
261
+ return;
262
+ }
263
+
264
+ // Cancel Command (dnxt cancel <task>)
265
+ if (command === 'cancel') {
266
+ const target = args.join(' ');
267
+ if (!target) return void await message.reply(`❌ Usage: ${prefix} cancel <task_name>`);
268
+
269
+ const tasks = (client as any)._activeTasks as Map<string, NodeJS.Timeout>;
270
+ if (!tasks) return void await message.reply('No active tasks to cancel.');
271
+
272
+ let found = false;
273
+ for (const [name, intervalId] of tasks.entries()) {
274
+ if (name.includes(target)) {
275
+ clearInterval(intervalId);
276
+ tasks.delete(name);
277
+ found = true;
278
+ await message.reply(`✅ Cancelled background task: \`${name.split('/').pop()}\``);
279
+ break;
280
+ }
281
+ }
282
+ if (!found) await message.reply('❌ Task not found.');
283
+ return;
284
+ }
285
+
292
286
  // Sync Command (dnxt sync)
293
287
  if (command === 'sync') {
294
288
  try {
@@ -301,37 +295,49 @@ export async function handleDNXT(message: Message, client: Client, devPrefix: 'd
301
295
  return;
302
296
  }
303
297
 
304
- // Restart Command (dnxt restart)
305
- if (command === 'restart') {
306
- await message.reply('🔄 Restarting framework...');
307
- client.destroy();
298
+ // SQL Command (dnxt sql <query>)
299
+ if (command === 'sql') {
300
+ const query = args.join(' ');
301
+ if (!query) return void await message.reply(`❌ Usage: ${prefix} sql <query>`);
308
302
 
309
- const { spawn } = require('child_process');
310
- const child = spawn(process.argv[0], process.argv.slice(1), {
311
- detached: true,
312
- stdio: 'ignore',
313
- cwd: process.cwd()
314
- });
315
- child.unref();
316
- process.exit(0);
303
+ try {
304
+ let res: any;
305
+ if (client.db && typeof client.db.$queryRawUnsafe === 'function') {
306
+ res = await client.db.$queryRawUnsafe(query); // Prisma fallback
307
+ } else if (client.db && typeof client.db.query === 'function') {
308
+ res = await client.db.query(query); // PG/MySQL fallback
309
+ } else {
310
+ return void await message.reply('❌ Your configured `client.db` does not expose a recognized raw SQL execution method (`$queryRawUnsafe` or `query`).');
311
+ }
312
+ const inspect = util.inspect(res, { depth: 2 });
313
+ await sendPaginatedText(message, `🗄️ **SQL Query**\n`, inspect, 'js');
314
+ } catch (e: any) {
315
+ await message.reply(`❌ **SQL Error:** ${e.message}`);
316
+ }
317
317
  return;
318
318
  }
319
319
 
320
- // Shutdown Command (dnxt shutdown | stop)
321
- if (command === 'shutdown' || command === 'stop') {
322
- await message.reply('🛑 Shutting down framework...');
323
- client.destroy();
324
- process.exit(0);
320
+ // Voice Command (dnxt vc)
321
+ if (command === 'vc' || command === 'voice') {
322
+ if (!message.guild) return void await message.reply(' This command must be used in a server.');
323
+ const me = message.guild.members.me;
324
+ if (!me?.voice?.channel) return void await message.reply('❌ Bot is not currently in a voice channel.');
325
+
326
+ const text = `🎙️ **Voice Debugger**\n` +
327
+ `Channel: <#${me.voice.channel.id}> (\`${me.voice.channel.id}\`)\n` +
328
+ `Muted: ${me.voice.mute} | Deafened: ${me.voice.deaf}\n` +
329
+ `Session ID: \`${me.voice.sessionId || 'None'}\``;
330
+ await message.reply(text);
325
331
  return;
326
332
  }
327
333
 
328
- await message.reply(`❓ Unknown ${matchedTrigger} command. Available: \`js, sh, git, cat, curl, in, debug, reload, sync, restart, shutdown\``);
334
+ await message.reply(`❓ Unknown ${prefix} command. Available: \`js, sh, git, cat, curl, su, in, source, debug, reload, tasks, cancel, sync, sql, vc\``);
329
335
  }
330
336
 
331
337
  async function sendPaginatedText(message: Message, header: string, content: string, language: string = '') {
332
- const maxLength = 800;
338
+ const maxLength = 1900;
333
339
  if (content.length <= maxLength) {
334
- await message.reply(buildDisplayMessage(`### ${header.replace(/\\*\\*/g, '')}\n\`\`\`${language}\n${content}\n\`\`\``));
340
+ await message.reply(`${header}\`\`\`${language}\n${content}\n\`\`\``);
335
341
  return;
336
342
  }
337
343
 
@@ -341,78 +347,33 @@ async function sendPaginatedText(message: Message, header: string, content: stri
341
347
  }
342
348
 
343
349
  let index = 0;
344
- const djs = require('discord.js');
345
-
346
- function buildPage(idx: number) {
347
- const text = `### ${header.replace(/\\*\\*/g, '')}\n\`\`\`${language}\n${chunks[idx]}\n\`\`\`\n> *Page ${idx + 1} of ${chunks.length}*`;
348
- const container = new djs.ContainerBuilder()
349
- .setAccentColor(0x525AF1)
350
- .addTextDisplayComponents(
351
- new djs.TextDisplayBuilder().setContent(text)
352
- );
353
-
354
- const row1 = new djs.ActionRowBuilder().addComponents(
355
- new djs.ButtonBuilder().setCustomId('first').setLabel('≪').setStyle(2),
356
- new djs.ButtonBuilder().setCustomId('prev').setLabel('<').setStyle(2),
357
- new djs.ButtonBuilder().setCustomId('goto').setLabel('⎘').setStyle(1),
358
- new djs.ButtonBuilder().setCustomId('next').setLabel('>').setStyle(2),
359
- new djs.ButtonBuilder().setCustomId('last').setLabel('≫').setStyle(2)
360
- );
361
-
362
- const row2 = new djs.ActionRowBuilder().addComponents(
363
- new djs.ButtonBuilder().setCustomId('stop').setLabel('✖ Close').setStyle(4)
364
- );
365
-
366
- container.addActionRowComponents(row1, row2);
367
- return { components: [container], flags: 32768 };
368
- }
350
+ const reply = await message.reply(`${header}\`\`\`${language}\n${chunks[index]}\n\`\`\`\n*Page 1 of ${chunks.length}*`);
369
351
 
370
- const reply = await message.reply(buildPage(index));
352
+ await reply.react('◀️');
353
+ await reply.react('▶️');
354
+ await reply.react('⏹️');
371
355
 
372
- const collector = reply.createMessageComponentCollector({
373
- filter: (i) => ['first', 'prev', 'goto', 'stop', 'next', 'last'].includes(i.customId) && i.user.id === message.author.id,
356
+ const collector = reply.createReactionCollector({
357
+ filter: (reaction, user) => ['◀️', '▶️', '⏹️'].includes(reaction.emoji.name!) && user.id === message.author.id,
374
358
  time: 120000
375
359
  });
376
360
 
377
- collector.on('collect', async (i) => {
378
- if (i.customId === 'first') {
379
- index = 0;
380
- } else if (i.customId === 'prev') {
361
+ collector.on('collect', async (reaction, user) => {
362
+ await reaction.users.remove(user.id).catch(() => null);
363
+
364
+ if (reaction.emoji.name === '◀️') {
381
365
  index = index > 0 ? index - 1 : index;
382
- } else if (i.customId === 'next') {
366
+ } else if (reaction.emoji.name === '▶️') {
383
367
  index = index < chunks.length - 1 ? index + 1 : index;
384
- } else if (i.customId === 'last') {
385
- index = chunks.length - 1;
386
- } else if (i.customId === 'goto') {
387
- const modal = new djs.ModalBuilder()
388
- .setCustomId('goto_modal')
389
- .setTitle('Go to Page');
390
- const input = new djs.TextInputBuilder()
391
- .setCustomId('page_num')
392
- .setLabel(`Page Number (1-${chunks.length})`)
393
- .setStyle(1)
394
- .setRequired(true);
395
- modal.addComponents(new djs.ActionRowBuilder().addComponents(input));
396
- await i.showModal(modal);
397
- try {
398
- const modalSubmit = await i.awaitModalSubmit({ filter: (mi) => mi.user.id === message.author.id && mi.customId === 'goto_modal', time: 60000 });
399
- const targetPage = parseInt(modalSubmit.fields.getTextInputValue('page_num'), 10);
400
- if (!isNaN(targetPage) && targetPage >= 1 && targetPage <= chunks.length) {
401
- index = targetPage - 1;
402
- }
403
- await modalSubmit.update(buildPage(index));
404
- } catch {}
405
- return;
406
- } else if (i.customId === 'stop') {
407
- await reply.delete().catch(() => null);
368
+ } else if (reaction.emoji.name === '⏹️') {
408
369
  collector.stop();
409
370
  return;
410
371
  }
411
372
 
412
- await i.update(buildPage(index));
373
+ await reply.edit(`${header}\`\`\`${language}\n${chunks[index]}\n\`\`\`\n*Page ${index + 1} of ${chunks.length}*`);
413
374
  });
414
375
 
415
376
  collector.on('end', () => {
416
- reply.edit({ components: [] }).catch(() => null);
377
+ reply.reactions.removeAll().catch(() => null);
417
378
  });
418
379
  }
@@ -14,17 +14,12 @@ const client = new DJSNextClient({
14
14
  client.start(process.env.DISCORD_TOKEN);
15
15
  `,
16
16
 
17
- ping: `/** @type {import('djs-next').FileCommand} */
18
- module.exports = {
19
- description: 'Replies with the actual bot latency!',
20
- execute: async (interaction, client) => {
21
- const sent = await interaction.reply({ content: 'Pinging...', withResponse: true });
22
- const msg = sent.resource?.message || await interaction.fetchReply();
23
- await interaction.editReply(\`Pong! 🏓\\nWebsocket Latency: \\\`\${client.ws.ping}ms\\\`\\nAPI Latency: \\\`\${msg.createdTimestamp - interaction.createdTimestamp}ms\\\`\`);
24
- },
25
- executeText: async (message, args, client) => {
26
- const sent = await message.reply('Pinging...');
27
- await sent.edit(\`Pong! 🏓\\nWebsocket Latency: \\\`\${client.ws.ping}ms\\\`\\nAPI Latency: \\\`\${sent.createdTimestamp - message.createdTimestamp}ms\\\`\`);
17
+ ping: `module.exports = {
18
+ command: {
19
+ description: 'Replies with Pong!',
20
+ execute: async (interaction) => {
21
+ await interaction.reply('Pong!');
22
+ }
28
23
  }
29
24
  };
30
25
  `,
@@ -14,17 +14,10 @@ const client = new DJSNextClient({
14
14
  client.start(process.env.DISCORD_TOKEN);
15
15
  `,
16
16
 
17
- ping: `/** @type {import('djs-next').FileCommand} */
18
- export default {
19
- description: 'Replies with the actual bot latency!',
20
- execute: async (interaction, client) => {
21
- const sent = await interaction.reply({ content: 'Pinging...', withResponse: true });
22
- const msg = sent.resource?.message || await interaction.fetchReply();
23
- await interaction.editReply(\`Pong! 🏓\\nWebsocket Latency: \\\`\${client.ws.ping}ms\\\`\\nAPI Latency: \\\`\${msg.createdTimestamp - interaction.createdTimestamp}ms\\\`\`);
24
- },
25
- executeText: async (message, args, client) => {
26
- const sent = await message.reply('Pinging...');
27
- await sent.edit(\`Pong! 🏓\\nWebsocket Latency: \\\`\${client.ws.ping}ms\\\`\\nAPI Latency: \\\`\${sent.createdTimestamp - message.createdTimestamp}ms\\\`\`);
17
+ ping: `export const command = {
18
+ description: 'Replies with Pong!',
19
+ execute: async (interaction) => {
20
+ await interaction.reply('Pong!');
28
21
  }
29
22
  };
30
23
  `,
@@ -16,18 +16,12 @@ client.start(process.env.DISCORD_TOKEN!);
16
16
 
17
17
  ping: `import { FileCommand } from 'djs-next';
18
18
 
19
- export default {
20
- description: 'Replies with the actual bot latency!',
21
- execute: async (interaction, client) => {
22
- const sent = await interaction.reply({ content: 'Pinging...', withResponse: true });
23
- const msg = sent.resource?.message || await interaction.fetchReply();
24
- await interaction.editReply(\`Pong! 🏓\\nWebsocket Latency: \\\`\${client.ws.ping}ms\\\`\\nAPI Latency: \\\`\${msg.createdTimestamp - interaction.createdTimestamp}ms\\\`\`);
25
- },
26
- executeText: async (message, args, client) => {
27
- const sent = await message.reply('Pinging...');
28
- await sent.edit(\`Pong! 🏓\\nWebsocket Latency: \\\`\${client.ws.ping}ms\\\`\\nAPI Latency: \\\`\${sent.createdTimestamp - message.createdTimestamp}ms\\\`\`);
19
+ export const command: FileCommand = {
20
+ description: 'Replies with Pong!',
21
+ execute: async (interaction) => {
22
+ await interaction.reply('Pong!');
29
23
  }
30
- } as FileCommand;
24
+ };
31
25
  `,
32
26
 
33
27
  ready: `import { DJSNextEvent, Events } from 'djs-next';
package/src/types.ts CHANGED
@@ -12,21 +12,8 @@ import {
12
12
  Message
13
13
  } from 'discord.js';
14
14
 
15
- export interface CooldownAdapter {
16
- get(commandId: string, userId: string): Promise<number | null> | number | null;
17
- set(commandId: string, userId: string, expirationTime: number): Promise<void> | void;
18
- }
19
-
20
15
  export interface DJSNextConfig {
21
16
  devGuildId?: string;
22
- errorLogChannelId?: string;
23
- responses?: {
24
- developerOnly?: string | null;
25
- guildOnly?: string | null;
26
- cooldown?: string | null;
27
- missingPerms?: string | null;
28
- errorBoundary?: string | null;
29
- };
30
17
  locales?: string[];
31
18
  defaultLocale?: string;
32
19
  directories?: {
@@ -36,7 +23,6 @@ export interface DJSNextConfig {
36
23
  tasks?: string;
37
24
  locales?: string;
38
25
  };
39
- cooldownAdapter?: CooldownAdapter;
40
26
  }
41
27
 
42
28
  export interface DJSNextClientOptions extends ClientOptions {
@@ -48,13 +34,9 @@ export interface DJSNextClientOptions extends ClientOptions {
48
34
  guildId?: string;
49
35
  developers?: string[];
50
36
  prefixes?: string[] | string;
51
- enableSlashCommands?: boolean;
52
- enableTextCommands?: boolean;
53
- enableMentionPrefix?: boolean | string[];
54
- enableNoPrefix?: boolean | string[];
37
+ enableMentionPrefix?: boolean;
55
38
  middleware?: (interaction: Interaction | Message, client: Client) => Promise<boolean> | boolean;
56
39
  config?: DJSNextConfig;
57
- db?: any;
58
40
  }
59
41
 
60
42
  export interface FileTask<DB = any> {
@@ -73,7 +55,6 @@ export interface FileCommand<DB = any> {
73
55
  developerOnly?: boolean;
74
56
  guildOnly?: boolean;
75
57
  aliases?: string[];
76
- preconditions?: string[];
77
58
  execute?: (interaction: ChatInputCommandInteraction, client: Client & { db: DB; t: Function; config: DJSNextConfig }) => Promise<void> | void;
78
59
  executeText?: (message: Message, args: string[], client: Client & { db: DB; t: Function; config: DJSNextConfig }) => Promise<void> | void;
79
60
  autocomplete?: (interaction: AutocompleteInteraction, client: Client & { db: DB; t: Function; config: DJSNextConfig }) => Promise<void> | void;
@@ -82,7 +63,6 @@ export interface FileCommand<DB = any> {
82
63
  export interface FileComponent<DB = any> {
83
64
  filepath?: string;
84
65
  customId?: string;
85
- preconditions?: string[];
86
66
  execute: (interaction: MessageComponentInteraction | ModalSubmitInteraction, client: Client & { db: DB; t: Function; config: DJSNextConfig }, params?: Record<string, string>) => Promise<void> | void;
87
67
  }
88
68