djs-next 0.0.1

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.

@@ -0,0 +1,37 @@
1
+ import { Client } from 'discord.js';
2
+ import fs from 'fs';
3
+ import { pathToFileURL } from 'url';
4
+ import { Event } from '../types.js';
5
+ import { getAllFiles } from './utils.js';
6
+
7
+ export async function loadEvents(client: Client, eventsDir: string) {
8
+ if (!fs.existsSync(eventsDir)) {
9
+ console.warn(`[djs-next] Events directory "${eventsDir}" does not exist.`);
10
+ return;
11
+ }
12
+
13
+ const eventFiles = getAllFiles(eventsDir);
14
+ let loadedEvents = 0;
15
+
16
+ for (const file of eventFiles) {
17
+ const eventModule = await import(pathToFileURL(file).href);
18
+ const eventData: Event<any> = eventModule.default?.event || eventModule.event || eventModule.default || eventModule;
19
+ if (eventData) eventData.filepath = file;
20
+
21
+ if (!eventData || !eventData.name || !eventData.execute) {
22
+ console.warn(`[djs-next] The event at ${file} is missing a required "name" or "execute" property.`);
23
+ continue;
24
+ }
25
+
26
+ if (eventData.once) {
27
+ client.once(eventData.name, (...args) => eventData.execute(client, ...args));
28
+ } else {
29
+ client.on(eventData.name, (...args) => eventData.execute(client, ...args));
30
+ }
31
+ loadedEvents++;
32
+ }
33
+
34
+ if (loadedEvents > 0) {
35
+ console.log(`[djs-next] Successfully loaded ${loadedEvents} events.`);
36
+ }
37
+ }
@@ -0,0 +1,38 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { pathToFileURL } from 'url';
4
+ import { Client } from 'discord.js';
5
+ import { FileTask } from '../types.js';
6
+ import { getAllFiles } from './utils.js';
7
+
8
+ export async function loadTasks(client: Client, tasksDir: string) {
9
+ if (!fs.existsSync(tasksDir)) return;
10
+
11
+ const files = getAllFiles(tasksDir);
12
+ let loaded = 0;
13
+
14
+ for (const file of files) {
15
+ const module = await import(pathToFileURL(file).href);
16
+ const taskData: FileTask = module.default || module.task || module;
17
+ if (taskData) taskData.filepath = file;
18
+
19
+ if (!taskData || !taskData.interval || !taskData.execute) continue;
20
+
21
+ const intervalId = setInterval(async () => {
22
+ try {
23
+ await taskData.execute(client);
24
+ } catch (error) {
25
+ console.error(`[djs-next] Background Task error at ${file}:`, error);
26
+ }
27
+ }, taskData.interval);
28
+
29
+ if (!(client as any)._activeTasks) (client as any)._activeTasks = new Map();
30
+ (client as any)._activeTasks.set(file, intervalId);
31
+
32
+ loaded++;
33
+ }
34
+
35
+ if (loaded > 0) {
36
+ console.log(`[djs-next] Successfully scheduled ${loaded} background tasks.`);
37
+ }
38
+ }
@@ -0,0 +1,25 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Recursively gets all files in a directory
6
+ */
7
+ export function getAllFiles(dirPath: string, arrayOfFiles: string[] = []): string[] {
8
+ const files = fs.readdirSync(dirPath);
9
+
10
+ files.forEach(file => {
11
+ const fullPath = path.join(dirPath, file);
12
+ if (fs.statSync(fullPath).isDirectory()) {
13
+ arrayOfFiles = getAllFiles(fullPath, arrayOfFiles);
14
+ } else {
15
+ if (file.endsWith('.js') || file.endsWith('.ts') || file.endsWith('.mjs') || file.endsWith('.cjs')) {
16
+ // Skip TypeScript declaration files
17
+ if (!file.endsWith('.d.ts')) {
18
+ arrayOfFiles.push(fullPath);
19
+ }
20
+ }
21
+ }
22
+ });
23
+
24
+ return arrayOfFiles;
25
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ import 'dotenv/config';
2
+ export * from './client.js';
3
+ export { DJSNextClientOptions, FileCommand, FileComponent, FileTask, Event as DJSNextEvent, DJSNextConfig, CooldownAdapter } from './types.js';
4
+ export * from './utils/paginate.js';
5
+ export * from './utils/prompts.js';
6
+ export * from './utils/configLoader.js';
7
+ export * from './utils/i18n.js';
8
+ export * from './utils/PaginationBuilder.js';
9
+ // Re-export everything from discord.js so users don't need to install it explicitly
10
+ export * from 'discord.js';
@@ -0,0 +1,418 @@
1
+ import { Message, EmbedBuilder, version as djsVersion } from 'discord.js';
2
+ import { exec } from 'child_process';
3
+ import util from 'util';
4
+ import os from 'os';
5
+ import { DJSNextClient } from '../client.js';
6
+ import { loadEvents } from '../handlers/eventHandler.js';
7
+ import { loadComponents } from '../handlers/componentHandler.js';
8
+ import { loadAndDeployCommands } from '../handlers/commandHandler.js';
9
+ import { loadTasks } from '../handlers/taskHandler.js';
10
+ import { loadLocales } from '../utils/i18n.js';
11
+
12
+ const execAsync = util.promisify(exec);
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> {
25
+ 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
+ }
46
+
47
+ let matchedTrigger = validTriggers.find(t => content === t || content.startsWith(`${t} `));
48
+ if (!matchedTrigger) return;
49
+
50
+ const args = content.slice(matchedTrigger.length).trim().split(/ +/g);
51
+ const command = args.shift()?.toLowerCase();
52
+
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
+ // Root dnxt command (Stats)
74
+ if (!command) {
75
+ const mem = process.memoryUsage();
76
+ const botPing = client.ws.ping;
77
+ const djs = require('discord.js');
78
+
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
+ });
96
+ return;
97
+ }
98
+
99
+ // Evaluation (js, eval, py)
100
+ if (command === 'js' || command === 'eval' || command === 'py') {
101
+ let code = args.join(' ');
102
+ if (code.startsWith('```js') || code.startsWith('```py')) code = code.replace(/^```[a-z]*|```$/g, '');
103
+ else if (code.startsWith('```')) code = code.replace(/^```|```$/g, '');
104
+
105
+ if (!code) return void await message.reply('❌ Please provide code to evaluate.');
106
+
107
+ try {
108
+ const start = process.hrtime.bigint();
109
+ const { commands, components, config } = client;
110
+
111
+ // eslint-disable-next-line no-eval
112
+ let evaled = await eval(`(async () => { ${code} })()`);
113
+ const end = process.hrtime.bigint();
114
+ const timeMs = Number(end - start) / 1e6;
115
+
116
+ if (typeof evaled !== 'string') evaled = util.inspect(evaled, { depth: 1, colors: true });
117
+
118
+ await sendPaginatedText(message, `✅ **Evaluated in ${timeMs.toFixed(3)}ms**\n`, evaled, 'ansi');
119
+ } catch (err: any) {
120
+ await sendPaginatedText(message, `❌ **Evaluation Error**\n`, err.message, 'ansi');
121
+ }
122
+ return;
123
+ }
124
+
125
+ // Execute Shell (sh, shell, git)
126
+ if (command === 'sh' || command === 'shell' || command === 'git') {
127
+ const cmd = command === 'git' ? 'git ' + args.join(' ') : args.join(' ');
128
+ if (!cmd) return void await message.reply('❌ Please provide a command to execute.');
129
+
130
+ try {
131
+ 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
+ }
142
+ const end = process.hrtime.bigint();
143
+ const timeMs = Number(end - start) / 1e6;
144
+
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');
151
+ } catch (err: any) {
152
+ await sendPaginatedText(message, `❌ **Shell Error**\n`, err.message, 'ansi');
153
+ }
154
+ return;
155
+ }
156
+
157
+ // Load / Unload / Reload
158
+ if (command === 'load' || command === 'unload' || command === 'reload') {
159
+ const target = args[0]?.toLowerCase();
160
+ try {
161
+ 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.`);
165
+ } 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.`);
172
+ } 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.`);
176
+ } 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.`);
179
+ } 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.`);
193
+ } else {
194
+ await message.reply('❌ Unknown target. Valid targets: `commands, events, components, locales, all`');
195
+ }
196
+ } catch (err: any) {
197
+ await message.reply(`❌ **${command.toUpperCase()} Error:** ${err.message}`);
198
+ }
199
+ return;
200
+ }
201
+
202
+ // Cat (Read File)
203
+ if (command === 'cat') {
204
+ const fs = await import('fs');
205
+ const path = await import('path');
206
+ const file = args.join(' ');
207
+ if (!file) return void await message.reply('❌ Please provide a file to read.');
208
+
209
+ try {
210
+ const content = fs.readFileSync(path.resolve(process.cwd(), file), 'utf8');
211
+ await sendPaginatedText(message, `📄 **${file}**\n`, content, file.split('.').pop() || '');
212
+ } catch (e: any) {
213
+ await message.reply(`❌ **Error reading file:** ${e.message}`);
214
+ }
215
+ return;
216
+ }
217
+
218
+
219
+
220
+
221
+
222
+ // Curl (dnxt curl <url>)
223
+ if (command === 'curl') {
224
+ const url = args[0];
225
+ if (!url) return void await message.reply('❌ Please provide a URL.');
226
+ try {
227
+ const res = await fetch(url);
228
+ const text = await res.text();
229
+ await sendPaginatedText(message, `🌐 **Fetched from \`${url}\`**\n`, text, 'html');
230
+ } catch (e: any) {
231
+ await message.reply(`❌ **Curl Error:** ${e.message}`);
232
+ }
233
+ return;
234
+ }
235
+
236
+ // Debug Command (dnxt debug <command>)
237
+ // In discord.py DNXT debug measures execution of a command.
238
+ // In our case we will run a js eval and time it explicitly with heap usage.
239
+ if (command === 'debug') {
240
+ let code = args.join(' ');
241
+ if (code.startsWith('```js') || code.startsWith('```py')) code = code.replace(/^```[a-z]*|```$/g, '');
242
+ else if (code.startsWith('```')) code = code.replace(/^```|```$/g, '');
243
+ if (!code) return void await message.reply('❌ Please provide code to debug.');
244
+
245
+ try {
246
+ const startMem = process.memoryUsage().heapUsed;
247
+ const start = process.hrtime.bigint();
248
+ const { commands, components, config } = client;
249
+
250
+ // eslint-disable-next-line no-eval
251
+ let evaled = await eval(`(async () => { ${code} })()`);
252
+
253
+ const end = process.hrtime.bigint();
254
+ const endMem = process.memoryUsage().heapUsed;
255
+ const timeMs = Number(end - start) / 1e6;
256
+ const memDiff = (endMem - startMem) / 1024 / 1024;
257
+
258
+ if (typeof evaled !== 'string') evaled = util.inspect(evaled, { depth: 1, colors: true });
259
+
260
+ await sendPaginatedText(message, `⏱️ **Debug Execution**\nTime: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`\n`, evaled, 'ansi');
261
+ } catch (err: any) {
262
+ await sendPaginatedText(message, `❌ **Debug Error**\n`, err.message, 'ansi');
263
+ }
264
+ return;
265
+ }
266
+
267
+ // In Command (dnxt in <channel_id> <command>)
268
+ if (command === 'in') {
269
+ const channelId = args.shift()?.replace(/<#|>/g, '');
270
+ const cmd = args.join(' ');
271
+ if (!channelId || !cmd) return void await message.reply(`❌ Usage: ${matchedTrigger} in <#channel|id> <command>`);
272
+ try {
273
+ const targetChannel = await client.channels.fetch(channelId);
274
+ if (!targetChannel || !targetChannel.isTextBased()) throw new Error('Invalid Text Channel.');
275
+
276
+ 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 });
285
+ client.emit('messageCreate', mockMessage as Message);
286
+ } catch (e: any) {
287
+ await message.reply(`❌ **In Error:** ${e.message}`);
288
+ }
289
+ return;
290
+ }
291
+
292
+ // Sync Command (dnxt sync)
293
+ if (command === 'sync') {
294
+ try {
295
+ await message.reply('🔄 Force syncing slash commands...');
296
+ await loadAndDeployCommands((client as any)._commandsDir, client.token!, (client as any)._clientId, (client as any)._guildId);
297
+ await message.reply('✅ Slash commands synchronized globally/locally.');
298
+ } catch (e: any) {
299
+ await message.reply(`❌ **Sync Error:** ${e.message}`);
300
+ }
301
+ return;
302
+ }
303
+
304
+ // Restart Command (dnxt restart)
305
+ if (command === 'restart') {
306
+ await message.reply('🔄 Restarting framework...');
307
+ client.destroy();
308
+
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);
317
+ return;
318
+ }
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);
325
+ return;
326
+ }
327
+
328
+ await message.reply(`❓ Unknown ${matchedTrigger} command. Available: \`js, sh, git, cat, curl, in, debug, reload, sync, restart, shutdown\``);
329
+ }
330
+
331
+ async function sendPaginatedText(message: Message, header: string, content: string, language: string = '') {
332
+ const maxLength = 800;
333
+ if (content.length <= maxLength) {
334
+ await message.reply(buildDisplayMessage(`### ${header.replace(/\\*\\*/g, '')}\n\`\`\`${language}\n${content}\n\`\`\``));
335
+ return;
336
+ }
337
+
338
+ const chunks: string[] = [];
339
+ for (let i = 0; i < content.length; i += maxLength) {
340
+ chunks.push(content.substring(i, i + maxLength));
341
+ }
342
+
343
+ 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
+ }
369
+
370
+ const reply = await message.reply(buildPage(index));
371
+
372
+ const collector = reply.createMessageComponentCollector({
373
+ filter: (i) => ['first', 'prev', 'goto', 'stop', 'next', 'last'].includes(i.customId) && i.user.id === message.author.id,
374
+ time: 120000
375
+ });
376
+
377
+ collector.on('collect', async (i) => {
378
+ if (i.customId === 'first') {
379
+ index = 0;
380
+ } else if (i.customId === 'prev') {
381
+ index = index > 0 ? index - 1 : index;
382
+ } else if (i.customId === 'next') {
383
+ 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);
408
+ collector.stop();
409
+ return;
410
+ }
411
+
412
+ await i.update(buildPage(index));
413
+ });
414
+
415
+ collector.on('end', () => {
416
+ reply.edit({ components: [] }).catch(() => null);
417
+ });
418
+ }
@@ -0,0 +1,54 @@
1
+ export const cjsTemplates = {
2
+ index: `const { DJSNextClient, GatewayIntentBits } = require('djs-next');
3
+ require('dotenv/config');
4
+
5
+ const client = new DJSNextClient({
6
+ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
7
+ commandsDir: './src/commands',
8
+ eventsDir: './src/events',
9
+ componentsDir: './src/components',
10
+ tasksDir: './src/tasks',
11
+ clientId: process.env.CLIENT_ID
12
+ });
13
+
14
+ client.start(process.env.DISCORD_TOKEN);
15
+ `,
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\\\`\`);
28
+ }
29
+ };
30
+ `,
31
+
32
+ ready: `const { Events } = require('djs-next');
33
+
34
+ module.exports = {
35
+ event: {
36
+ name: Events.ClientReady,
37
+ once: true,
38
+ execute: (client) => {
39
+ console.log('Ready! Logged in as ' + client.user?.tag);
40
+ }
41
+ }
42
+ };
43
+ `,
44
+
45
+ healthcheck: `module.exports = {
46
+ task: {
47
+ interval: 60000,
48
+ execute: async (client) => {
49
+ console.log('[Task] Healthcheck completed.');
50
+ }
51
+ }
52
+ };
53
+ `
54
+ };
@@ -0,0 +1,50 @@
1
+ export const esmTemplates = {
2
+ index: `import { DJSNextClient, GatewayIntentBits } from 'djs-next';
3
+ import 'dotenv/config';
4
+
5
+ const client = new DJSNextClient({
6
+ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
7
+ commandsDir: './src/commands',
8
+ eventsDir: './src/events',
9
+ componentsDir: './src/components',
10
+ tasksDir: './src/tasks',
11
+ clientId: process.env.CLIENT_ID
12
+ });
13
+
14
+ client.start(process.env.DISCORD_TOKEN);
15
+ `,
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\\\`\`);
28
+ }
29
+ };
30
+ `,
31
+
32
+ ready: `import { Events } from 'djs-next';
33
+
34
+ export const event = {
35
+ name: Events.ClientReady,
36
+ once: true,
37
+ execute: (client) => {
38
+ console.log('Ready! Logged in as ' + client.user?.tag);
39
+ }
40
+ };
41
+ `,
42
+
43
+ healthcheck: `export const task = {
44
+ interval: 60000,
45
+ execute: async (client) => {
46
+ console.log('[Task] Healthcheck completed.');
47
+ }
48
+ };
49
+ `
50
+ };