djs-next 1.0.0-dev.1 → 1.0.0-dev.3

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.

package/dist/index.mjs CHANGED
@@ -5,6 +5,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
5
5
  throw Error('Dynamic require of "' + x + '" is not supported');
6
6
  });
7
7
 
8
+ // src/index.ts
9
+ import "dotenv/config";
10
+
8
11
  // src/client.ts
9
12
  import { Client, Collection as Collection3 } from "discord.js";
10
13
 
@@ -252,9 +255,9 @@ function loadLocales(localesDir, defaultLocale) {
252
255
  for (const file of files) {
253
256
  if (file.endsWith(".json")) {
254
257
  const lang = file.replace(".json", "");
255
- const content = fs7.readFileSync(path5.join(localesDir, file), "utf8");
258
+ const content2 = fs7.readFileSync(path5.join(localesDir, file), "utf8");
256
259
  try {
257
- localesCache[lang] = JSON.parse(content);
260
+ localesCache[lang] = JSON.parse(content2);
258
261
  } catch (e) {
259
262
  console.error(`[djs-next] Failed to parse locale file: ${file}`, e);
260
263
  }
@@ -288,26 +291,92 @@ function getLocalesCache() {
288
291
  }
289
292
 
290
293
  // src/plugins/dnxt.ts
294
+ import { version as djsVersion } from "discord.js";
291
295
  import { exec } from "child_process";
292
296
  import util from "util";
293
297
  import os from "os";
294
298
  var execAsync = util.promisify(exec);
295
- async function handleDNXT(message, client, prefix = "dnxt") {
299
+ function buildDisplayMessage(content2, color = 5397233) {
300
+ const djs = __require("discord.js");
301
+ const container = new djs.ContainerBuilder().setAccentColor(color).addTextDisplayComponents(
302
+ new djs.TextDisplayBuilder().setContent(content2)
303
+ );
304
+ return { components: [container], flags: 32768 };
305
+ }
306
+ async function handleDNXT(message, client, devPrefix) {
296
307
  if (message.author.bot) return;
297
- if (!client["_developers"].includes(message.author.id)) return;
298
- if (!message.content.startsWith(prefix)) return;
299
- const args = message.content.slice(prefix.length).trim().split(/ +/);
308
+ if (!client._developers.includes(message.author.id)) return;
309
+ if (client.config?.devGuildId && message.guildId !== client.config.devGuildId) return;
310
+ const originalReply = message.reply.bind(message);
311
+ message.reply = (async (content2) => {
312
+ if (typeof content2 === "string") {
313
+ return await originalReply({ ...buildDisplayMessage(content2), allowedMentions: { repliedUser: false } });
314
+ }
315
+ if (!content2.allowedMentions) content2.allowedMentions = { repliedUser: false };
316
+ return await originalReply(content2);
317
+ });
318
+ const content = message.content.trim();
319
+ const validTriggers = [devPrefix];
320
+ const clientPrefixes = client._prefixes || [];
321
+ for (const p of clientPrefixes) {
322
+ if (p !== "") validTriggers.push(`${p}${devPrefix}`);
323
+ }
324
+ let matchedTrigger = validTriggers.find((t) => content === t || content.startsWith(`${t} `));
325
+ if (!matchedTrigger) return;
326
+ const args = content.slice(matchedTrigger.length).trim().split(/ +/g);
300
327
  const command = args.shift()?.toLowerCase();
328
+ if (command === "help") {
329
+ const djs = __require("discord.js");
330
+ const container = new djs.ContainerBuilder().setAccentColor(5397233).addTextDisplayComponents(
331
+ new djs.TextDisplayBuilder().setContent(`# \u{1F4D6} DNXT Toolkit Reference
332
+ > Current prefix trigger: \`${matchedTrigger}\``)
333
+ ).addSeparatorComponents(new djs.SeparatorBuilder()).addTextDisplayComponents(
334
+ new djs.TextDisplayBuilder().setContent(`### \u{1F4CA} Core Framework
335
+ - \`${matchedTrigger}\` \u2014 Developer system dashboard
336
+ - \`${matchedTrigger} help\` \u2014 Shows this reference menu`),
337
+ new djs.TextDisplayBuilder().setContent(`### \u{1F4BB} Execution & Diagnostics
338
+ - \`${matchedTrigger} js <code>\` \u2014 Evaluates raw JS code
339
+ - \`${matchedTrigger} sh <cmd>\` \u2014 Runs terminal shell script
340
+ - \`${matchedTrigger} debug <code>\` \u2014 Evaluates JS with precise memory deltas`),
341
+ new djs.TextDisplayBuilder().setContent(`### \u{1F4C2} File System & Network
342
+ - \`${matchedTrigger} cat <file>\` \u2014 Reads file contents
343
+ - \`${matchedTrigger} curl <url>\` \u2014 Fetches remote URL data
344
+ - \`${matchedTrigger} git <cmd>\` \u2014 Executes git repository commands`),
345
+ new djs.TextDisplayBuilder().setContent(`### \u{1F9F0} Utilities
346
+ - \`${matchedTrigger} <load|unload|reload> <target>\` \u2014 Manages system modules
347
+ - \`${matchedTrigger} sync\` \u2014 Forces global slash command sync
348
+ - \`${matchedTrigger} in <channel> <cmd>\` \u2014 Executes command in target channel
349
+ - \`${matchedTrigger} restart\` \u2014 Restarts the bot completely
350
+ - \`${matchedTrigger} shutdown\` \u2014 Stops the bot completely`)
351
+ );
352
+ await message.reply({ components: [container], flags: 32768, allowedMentions: { repliedUser: false } });
353
+ return;
354
+ }
301
355
  if (!command) {
302
356
  const mem = process.memoryUsage();
303
- const discordJsVersion = __require("discord.js/package.json").version;
304
357
  const botPing = client.ws.ping;
305
- const text = `Module was loaded <t:${Math.floor((Date.now() - client.uptime) / 1e3)}:R>.
306
- DNXT framework plugin, discord.js \`${discordJsVersion}\`, \`Node.js ${process.version}\` on \`${os.type()}\`.
307
- Latencies: \`${botPing}ms\` websocket ping.
308
- Memory: \`${(mem.rss / 1024 / 1024).toFixed(2)} MB\` physical, \`${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB\` heap.
309
- System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2)}\` hrs system uptime.`;
310
- await message.reply(text);
358
+ const djs = __require("discord.js");
359
+ const container = new djs.ContainerBuilder().setAccentColor(5397233).addTextDisplayComponents(
360
+ new djs.TextDisplayBuilder().setContent(`# \u{1F6E0}\uFE0F Developer System Dashboard
361
+ > **DNXT Framework Engine**`)
362
+ ).addSeparatorComponents(new djs.SeparatorBuilder()).addTextDisplayComponents(
363
+ new djs.TextDisplayBuilder().setContent(`### \u{1F4E1} Network Status
364
+ - **System Uptime:** <t:${Math.floor((Date.now() - client.uptime) / 1e3)}:R>
365
+ - **WebSocket Latency:** \`${botPing}ms\``),
366
+ new djs.TextDisplayBuilder().setContent(`### \u{1F4E6} Host Environment
367
+ - **Discord.js Library:** \`v${djsVersion}\`
368
+ - **Node.js Runtime:** \`${process.version}\`
369
+ - **Operating System:** \`${os.type()}\` (\`${os.cpus().length}\` thread cores, \`${(os.uptime() / 60 / 60).toFixed(2)}\` hrs uptime)`),
370
+ new djs.TextDisplayBuilder().setContent(`### \u{1F9E0} Resource Utilization
371
+ - **Physical Memory:** \`${(mem.rss / 1024 / 1024).toFixed(2)} MB\`
372
+ - **Heap Allocated:** \`${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB\``)
373
+ );
374
+ await message.reply({
375
+ components: [container],
376
+ flags: 32768,
377
+ // MessageFlags.IsComponentsV2
378
+ allowedMentions: { repliedUser: false }
379
+ });
311
380
  return;
312
381
  }
313
382
  if (command === "js" || command === "eval" || command === "py") {
@@ -321,12 +390,12 @@ System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2
321
390
  let evaled = await eval(`(async () => { ${code} })()`);
322
391
  const end = process.hrtime.bigint();
323
392
  const timeMs = Number(end - start) / 1e6;
324
- if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1 });
393
+ if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1, colors: true });
325
394
  await sendPaginatedText(message, `\u2705 **Evaluated in ${timeMs.toFixed(3)}ms**
326
- `, evaled, "js");
395
+ `, evaled, "ansi");
327
396
  } catch (err) {
328
397
  await sendPaginatedText(message, `\u274C **Evaluation Error**
329
- `, err.message, "js");
398
+ `, err.message, "ansi");
330
399
  }
331
400
  return;
332
401
  }
@@ -335,52 +404,74 @@ System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2
335
404
  if (!cmd) return void await message.reply("\u274C Please provide a command to execute.");
336
405
  try {
337
406
  const start2 = process.hrtime.bigint();
338
- const { stdout, stderr } = await execAsync(cmd);
407
+ let stdout = "", stderr = "", code2 = 0;
408
+ try {
409
+ const result = await execAsync(cmd);
410
+ stdout = result.stdout;
411
+ stderr = result.stderr;
412
+ } catch (err) {
413
+ stdout = err.stdout || "";
414
+ stderr = err.stderr || err.message || "";
415
+ code2 = err.code || 1;
416
+ }
339
417
  const end2 = process.hrtime.bigint();
340
418
  const timeMs2 = Number(end2 - start2) / 1e6;
341
- const result = stdout || stderr || "No output.";
419
+ let resultText = `$ ${cmd}
420
+ `;
421
+ if (stdout) resultText += `${stdout}
422
+ `;
423
+ if (stderr) resultText += `${stderr}
424
+ `;
425
+ resultText += `
426
+ [status] Return code ${code2}`;
342
427
  await sendPaginatedText(message, `\u2705 **Executed in ${timeMs2.toFixed(3)}ms**
343
- `, result, "sh");
428
+ `, resultText, "ansi");
344
429
  } catch (err) {
345
430
  await sendPaginatedText(message, `\u274C **Shell Error**
346
- `, err.message, "sh");
431
+ `, err.message, "ansi");
347
432
  }
348
433
  return;
349
434
  }
350
- if (command === "reload" || command === "load") {
435
+ if (command === "load" || command === "unload" || command === "reload") {
351
436
  const target = args[0]?.toLowerCase();
352
437
  try {
353
438
  if (target === "commands" && client["_commandsDir"]) {
354
- client.commands.clear();
355
- client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
356
- await message.reply("\u2705 Reloaded commands.");
439
+ if (command === "unload" || command === "reload") client.commands.clear();
440
+ if (command === "load" || command === "reload") client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
441
+ await message.reply(`\u2705 Successfully ${command}ed commands.`);
357
442
  } else if (target === "events" && client["_eventsDir"]) {
358
- client.removeAllListeners();
359
- client["attachCoreListeners"]();
360
- await loadEvents(client, client["_eventsDir"]);
361
- await message.reply("\u2705 Reloaded events.");
443
+ if (command === "unload" || command === "reload") {
444
+ client.removeAllListeners();
445
+ client["attachCoreListeners"]();
446
+ }
447
+ if (command === "load" || command === "reload") await loadEvents(client, client["_eventsDir"]);
448
+ await message.reply(`\u2705 Successfully ${command}ed events.`);
362
449
  } else if (target === "components" && client["_componentsDir"]) {
363
- client.components.clear();
364
- client.components = await loadComponents(client["_componentsDir"]);
365
- await message.reply("\u2705 Reloaded components.");
450
+ if (command === "unload" || command === "reload") client.components.clear();
451
+ if (command === "load" || command === "reload") client.components = await loadComponents(client["_componentsDir"]);
452
+ await message.reply(`\u2705 Successfully ${command}ed components.`);
366
453
  } else if (target === "locales" && client["_localesDir"]) {
367
- loadLocales(client["_localesDir"], client.config.defaultLocale);
368
- await message.reply("\u2705 Reloaded locales.");
454
+ if (command === "load" || command === "reload") loadLocales(client["_localesDir"], client.config.defaultLocale);
455
+ await message.reply(`\u2705 Successfully ${command}ed locales.`);
369
456
  } else if (target === "all" || !target) {
370
- client.removeAllListeners();
371
- client["attachCoreListeners"]();
372
- client.commands.clear();
373
- client.components.clear();
374
- if (client["_eventsDir"]) await loadEvents(client, client["_eventsDir"]);
375
- if (client["_componentsDir"]) client.components = await loadComponents(client["_componentsDir"]);
376
- if (client["_localesDir"]) loadLocales(client["_localesDir"], client.config.defaultLocale);
377
- if (client["_commandsDir"]) client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
378
- await message.reply("\u2705 Reloaded all framework modules.");
457
+ if (command === "unload" || command === "reload") {
458
+ client.removeAllListeners();
459
+ client["attachCoreListeners"]();
460
+ client.commands.clear();
461
+ client.components.clear();
462
+ }
463
+ if (command === "load" || command === "reload") {
464
+ if (client["_eventsDir"]) await loadEvents(client, client["_eventsDir"]);
465
+ if (client["_componentsDir"]) client.components = await loadComponents(client["_componentsDir"]);
466
+ if (client["_localesDir"]) loadLocales(client["_localesDir"], client.config.defaultLocale);
467
+ if (client["_commandsDir"]) client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
468
+ }
469
+ await message.reply(`\u2705 Successfully ${command}ed all framework modules.`);
379
470
  } else {
380
471
  await message.reply("\u274C Unknown target. Valid targets: `commands, events, components, locales, all`");
381
472
  }
382
473
  } catch (err) {
383
- await message.reply(`\u274C **Reload Error:** ${err.message}`);
474
+ await message.reply(`\u274C **${command.toUpperCase()} Error:** ${err.message}`);
384
475
  }
385
476
  return;
386
477
  }
@@ -390,49 +481,14 @@ System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2
390
481
  const file = args.join(" ");
391
482
  if (!file) return void await message.reply("\u274C Please provide a file to read.");
392
483
  try {
393
- const content = fs9.readFileSync(path7.resolve(process.cwd(), file), "utf8");
484
+ const content2 = fs9.readFileSync(path7.resolve(process.cwd(), file), "utf8");
394
485
  await sendPaginatedText(message, `\u{1F4C4} **${file}**
395
- `, content, file.split(".").pop() || "");
486
+ `, content2, file.split(".").pop() || "");
396
487
  } catch (e) {
397
488
  await message.reply(`\u274C **Error reading file:** ${e.message}`);
398
489
  }
399
490
  return;
400
491
  }
401
- if (command === "su" || command === "sudo") {
402
- const targetUserId = args.shift();
403
- const cmd = args.join(" ");
404
- if (!targetUserId || !cmd) return void await message.reply(`\u274C Usage: ${prefix} su <user_id> <command>`);
405
- try {
406
- const targetUser = await client.users.fetch(targetUserId.replace(/<@!?|>/g, ""));
407
- if (!targetUser) throw new Error("User not found.");
408
- const mockMessage = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
409
- mockMessage.author = targetUser;
410
- if (message.guild) {
411
- mockMessage.member = await message.guild.members.fetch(targetUser.id).catch(() => null);
412
- }
413
- mockMessage.content = cmd;
414
- client.emit("messageCreate", mockMessage);
415
- await message.reply(`\u2705 Invoked \`${cmd}\` as **${targetUser.tag}**.`);
416
- } catch (e) {
417
- await message.reply(`\u274C **Sudo Error:** ${e.message}`);
418
- }
419
- return;
420
- }
421
- if (command === "source" || command === "src") {
422
- const target = args.join(" ");
423
- if (!target) return void await message.reply("\u274C Please provide a command name.");
424
- const cmdData = client.commands.get(target);
425
- if (!cmdData || !cmdData.filepath) return void await message.reply("\u274C Command not found or has no associated filepath.");
426
- try {
427
- const fs9 = await import("fs");
428
- const content = fs9.readFileSync(cmdData.filepath, "utf8");
429
- await sendPaginatedText(message, `\u{1F4C4} **Source of \`${target}\`**
430
- `, content, cmdData.filepath.split(".").pop() || "");
431
- } catch (e) {
432
- await message.reply(`\u274C **Error reading source:** ${e.message}`);
433
- }
434
- return;
435
- }
436
492
  if (command === "curl") {
437
493
  const url = args[0];
438
494
  if (!url) return void await message.reply("\u274C Please provide a URL.");
@@ -460,64 +516,38 @@ System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2
460
516
  const endMem = process.memoryUsage().heapUsed;
461
517
  const timeMs = Number(end - start) / 1e6;
462
518
  const memDiff = (endMem - startMem) / 1024 / 1024;
463
- if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1 });
519
+ if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1, colors: true });
464
520
  await sendPaginatedText(message, `\u23F1\uFE0F **Debug Execution**
465
521
  Time: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`
466
- `, evaled, "js");
522
+ `, evaled, "ansi");
467
523
  } catch (err) {
468
524
  await sendPaginatedText(message, `\u274C **Debug Error**
469
- `, err.message, "js");
525
+ `, err.message, "ansi");
470
526
  }
471
527
  return;
472
528
  }
473
529
  if (command === "in") {
474
530
  const channelId = args.shift()?.replace(/<#|>/g, "");
475
531
  const cmd = args.join(" ");
476
- if (!channelId || !cmd) return void await message.reply(`\u274C Usage: ${prefix} in <channel> <command>`);
532
+ if (!channelId || !cmd) return void await message.reply(`\u274C Usage: ${matchedTrigger} in <#channel|id> <command>`);
477
533
  try {
478
534
  const targetChannel = await client.channels.fetch(channelId);
479
535
  if (!targetChannel || !targetChannel.isTextBased()) throw new Error("Invalid Text Channel.");
480
536
  const mockMessage = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
481
- mockMessage.channel = targetChannel;
482
- mockMessage.channelId = targetChannel.id;
483
- mockMessage.content = cmd;
537
+ Object.defineProperty(mockMessage, "client", { value: client, configurable: true });
538
+ if (message.guild) {
539
+ Object.defineProperty(mockMessage, "guild", { value: message.guild, configurable: true });
540
+ Object.defineProperty(mockMessage, "guildId", { value: message.guildId, configurable: true });
541
+ }
542
+ Object.defineProperty(mockMessage, "channel", { value: targetChannel, configurable: true });
543
+ Object.defineProperty(mockMessage, "channelId", { value: targetChannel.id, configurable: true });
544
+ Object.defineProperty(mockMessage, "content", { value: cmd, configurable: true });
484
545
  client.emit("messageCreate", mockMessage);
485
- await message.reply(`\u2705 Redirected execution to <#${targetChannel.id}>.`);
486
546
  } catch (e) {
487
547
  await message.reply(`\u274C **In Error:** ${e.message}`);
488
548
  }
489
549
  return;
490
550
  }
491
- if (command === "tasks") {
492
- const tasks = client._activeTasks;
493
- if (!tasks || tasks.size === 0) return void await message.reply("No active background tasks running.");
494
- let text = `\u2699\uFE0F **Active Background Tasks (${tasks.size})**
495
- `;
496
- for (const [name] of tasks.entries()) {
497
- text += `- \`${name.split("/").pop()}\`
498
- `;
499
- }
500
- await sendPaginatedText(message, "", text, "");
501
- return;
502
- }
503
- if (command === "cancel") {
504
- const target = args.join(" ");
505
- if (!target) return void await message.reply(`\u274C Usage: ${prefix} cancel <task_name>`);
506
- const tasks = client._activeTasks;
507
- if (!tasks) return void await message.reply("No active tasks to cancel.");
508
- let found = false;
509
- for (const [name, intervalId] of tasks.entries()) {
510
- if (name.includes(target)) {
511
- clearInterval(intervalId);
512
- tasks.delete(name);
513
- found = true;
514
- await message.reply(`\u2705 Cancelled background task: \`${name.split("/").pop()}\``);
515
- break;
516
- }
517
- }
518
- if (!found) await message.reply("\u274C Task not found.");
519
- return;
520
- }
521
551
  if (command === "sync") {
522
552
  try {
523
553
  await message.reply("\u{1F504} Force syncing slash commands...");
@@ -528,80 +558,102 @@ Time: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`
528
558
  }
529
559
  return;
530
560
  }
531
- if (command === "sql") {
532
- const query = args.join(" ");
533
- if (!query) return void await message.reply(`\u274C Usage: ${prefix} sql <query>`);
534
- try {
535
- let res;
536
- if (client.db && typeof client.db.$queryRawUnsafe === "function") {
537
- res = await client.db.$queryRawUnsafe(query);
538
- } else if (client.db && typeof client.db.query === "function") {
539
- res = await client.db.query(query);
540
- } else {
541
- return void await message.reply("\u274C Your configured `client.db` does not expose a recognized raw SQL execution method (`$queryRawUnsafe` or `query`).");
542
- }
543
- const inspect = util.inspect(res, { depth: 2 });
544
- await sendPaginatedText(message, `\u{1F5C4}\uFE0F **SQL Query**
545
- `, inspect, "js");
546
- } catch (e) {
547
- await message.reply(`\u274C **SQL Error:** ${e.message}`);
548
- }
561
+ if (command === "restart") {
562
+ await message.reply("\u{1F504} Restarting framework...");
563
+ client.destroy();
564
+ const { spawn } = __require("child_process");
565
+ const child = spawn(process.argv[0], process.argv.slice(1), {
566
+ detached: true,
567
+ stdio: "ignore",
568
+ cwd: process.cwd()
569
+ });
570
+ child.unref();
571
+ process.exit(0);
549
572
  return;
550
573
  }
551
- if (command === "vc" || command === "voice") {
552
- if (!message.guild) return void await message.reply("\u274C This command must be used in a server.");
553
- const me = message.guild.members.me;
554
- if (!me?.voice?.channel) return void await message.reply("\u274C Bot is not currently in a voice channel.");
555
- const text = `\u{1F399}\uFE0F **Voice Debugger**
556
- Channel: <#${me.voice.channel.id}> (\`${me.voice.channel.id}\`)
557
- Muted: ${me.voice.mute} | Deafened: ${me.voice.deaf}
558
- Session ID: \`${me.voice.sessionId || "None"}\``;
559
- await message.reply(text);
574
+ if (command === "shutdown" || command === "stop") {
575
+ await message.reply("\u{1F6D1} Shutting down framework...");
576
+ client.destroy();
577
+ process.exit(0);
560
578
  return;
561
579
  }
562
- await message.reply(`\u2753 Unknown ${prefix} command. Available: \`js, sh, git, cat, curl, su, in, source, debug, reload, tasks, cancel, sync, sql, vc\``);
580
+ await message.reply(`\u2753 Unknown ${matchedTrigger} command. Available: \`js, sh, git, cat, curl, in, debug, reload, sync, restart, shutdown\``);
563
581
  }
564
- async function sendPaginatedText(message2, header, content, language = "") {
565
- const maxLength = 1900;
566
- if (content.length <= maxLength) {
567
- await message2.reply(`${header}\`\`\`${language}
568
- ${content}
569
- \`\`\``);
582
+ async function sendPaginatedText(message2, header, content2, language = "") {
583
+ const maxLength = 800;
584
+ if (content2.length <= maxLength) {
585
+ await message2.reply(buildDisplayMessage(`### ${header.replace(/\\*\\*/g, "")}
586
+ \`\`\`${language}
587
+ ${content2}
588
+ \`\`\``));
570
589
  return;
571
590
  }
572
591
  const chunks = [];
573
- for (let i = 0; i < content.length; i += maxLength) {
574
- chunks.push(content.substring(i, i + maxLength));
592
+ for (let i = 0; i < content2.length; i += maxLength) {
593
+ chunks.push(content2.substring(i, i + maxLength));
575
594
  }
576
595
  let index = 0;
577
- const reply = await message2.reply(`${header}\`\`\`${language}
578
- ${chunks[index]}
596
+ const djs = __require("discord.js");
597
+ function buildPage(idx) {
598
+ const text = `### ${header.replace(/\\*\\*/g, "")}
599
+ \`\`\`${language}
600
+ ${chunks[idx]}
579
601
  \`\`\`
580
- *Page 1 of ${chunks.length}*`);
581
- await reply.react("\u25C0\uFE0F");
582
- await reply.react("\u25B6\uFE0F");
583
- await reply.react("\u23F9\uFE0F");
584
- const collector = reply.createReactionCollector({
585
- filter: (reaction, user) => ["\u25C0\uFE0F", "\u25B6\uFE0F", "\u23F9\uFE0F"].includes(reaction.emoji.name) && user.id === message2.author.id,
602
+ > *Page ${idx + 1} of ${chunks.length}*`;
603
+ const container = new djs.ContainerBuilder().setAccentColor(5397233).addTextDisplayComponents(
604
+ new djs.TextDisplayBuilder().setContent(text)
605
+ );
606
+ const row1 = new djs.ActionRowBuilder().addComponents(
607
+ new djs.ButtonBuilder().setCustomId("first").setLabel("\u226A").setStyle(2),
608
+ new djs.ButtonBuilder().setCustomId("prev").setLabel("\uFF1C").setStyle(2),
609
+ new djs.ButtonBuilder().setCustomId("goto").setLabel("\u2398").setStyle(1),
610
+ new djs.ButtonBuilder().setCustomId("next").setLabel("\uFF1E").setStyle(2),
611
+ new djs.ButtonBuilder().setCustomId("last").setLabel("\u226B").setStyle(2)
612
+ );
613
+ const row2 = new djs.ActionRowBuilder().addComponents(
614
+ new djs.ButtonBuilder().setCustomId("stop").setLabel("\u2716 Close").setStyle(4)
615
+ );
616
+ container.addActionRowComponents(row1, row2);
617
+ return { components: [container], flags: 32768 };
618
+ }
619
+ const reply = await message2.reply(buildPage(index));
620
+ const collector = reply.createMessageComponentCollector({
621
+ filter: (i) => ["first", "prev", "goto", "stop", "next", "last"].includes(i.customId) && i.user.id === message2.author.id,
586
622
  time: 12e4
587
623
  });
588
- collector.on("collect", async (reaction, user) => {
589
- await reaction.users.remove(user.id).catch(() => null);
590
- if (reaction.emoji.name === "\u25C0\uFE0F") {
624
+ collector.on("collect", async (i) => {
625
+ if (i.customId === "first") {
626
+ index = 0;
627
+ } else if (i.customId === "prev") {
591
628
  index = index > 0 ? index - 1 : index;
592
- } else if (reaction.emoji.name === "\u25B6\uFE0F") {
629
+ } else if (i.customId === "next") {
593
630
  index = index < chunks.length - 1 ? index + 1 : index;
594
- } else if (reaction.emoji.name === "\u23F9\uFE0F") {
631
+ } else if (i.customId === "last") {
632
+ index = chunks.length - 1;
633
+ } else if (i.customId === "goto") {
634
+ const modal = new djs.ModalBuilder().setCustomId("goto_modal").setTitle("Go to Page");
635
+ const input = new djs.TextInputBuilder().setCustomId("page_num").setLabel(`Page Number (1-${chunks.length})`).setStyle(1).setRequired(true);
636
+ modal.addComponents(new djs.ActionRowBuilder().addComponents(input));
637
+ await i.showModal(modal);
638
+ try {
639
+ const modalSubmit = await i.awaitModalSubmit({ filter: (mi) => mi.user.id === message2.author.id && mi.customId === "goto_modal", time: 6e4 });
640
+ const targetPage = parseInt(modalSubmit.fields.getTextInputValue("page_num"), 10);
641
+ if (!isNaN(targetPage) && targetPage >= 1 && targetPage <= chunks.length) {
642
+ index = targetPage - 1;
643
+ }
644
+ await modalSubmit.update(buildPage(index));
645
+ } catch {
646
+ }
647
+ return;
648
+ } else if (i.customId === "stop") {
649
+ await reply.delete().catch(() => null);
595
650
  collector.stop();
596
651
  return;
597
652
  }
598
- await reply.edit(`${header}\`\`\`${language}
599
- ${chunks[index]}
600
- \`\`\`
601
- *Page ${index + 1} of ${chunks.length}*`);
653
+ await i.update(buildPage(index));
602
654
  });
603
655
  collector.on("end", () => {
604
- reply.reactions.removeAll().catch(() => null);
656
+ reply.edit({ components: [] }).catch(() => null);
605
657
  });
606
658
  }
607
659
 
@@ -622,6 +674,11 @@ var DJSNextClient = class extends Client {
622
674
  _guildId;
623
675
  _developers;
624
676
  _middleware;
677
+ _prefixes;
678
+ _enableSlashCommands;
679
+ _enableTextCommands;
680
+ _enableMentionPrefix;
681
+ _enableNoPrefix;
625
682
  constructor(options) {
626
683
  super(options);
627
684
  this.commands = new Collection3();
@@ -635,6 +692,14 @@ var DJSNextClient = class extends Client {
635
692
  this._guildId = options.guildId;
636
693
  this._developers = options.developers || [];
637
694
  this._middleware = options.middleware;
695
+ const prefs = options.prefixes || [];
696
+ this._prefixes = Array.isArray(prefs) ? prefs : [prefs];
697
+ this._prefixes = this._prefixes.filter((p) => p !== "");
698
+ this._enableSlashCommands = options.enableSlashCommands ?? true;
699
+ this._enableTextCommands = options.enableTextCommands ?? true;
700
+ this._enableMentionPrefix = options.enableMentionPrefix ?? true;
701
+ this._enableNoPrefix = options.enableNoPrefix ?? false;
702
+ if (options.db) this.db = options.db;
638
703
  this.attachCoreListeners();
639
704
  }
640
705
  attachCoreListeners() {
@@ -649,6 +714,7 @@ var DJSNextClient = class extends Client {
649
714
  }
650
715
  }
651
716
  if (interaction.isChatInputCommand()) {
717
+ if (!this._enableSlashCommands) return;
652
718
  let commandKey = interaction.commandName;
653
719
  const group = interaction.options.getSubcommandGroup(false);
654
720
  const sub = interaction.options.getSubcommand(false);
@@ -656,48 +722,11 @@ var DJSNextClient = class extends Client {
656
722
  if (sub) commandKey += ` ${sub}`;
657
723
  const command2 = this.commands.get(commandKey);
658
724
  if (!command2 || !command2.execute) return;
659
- if (command2.developerOnly && !this._developers.includes(interaction.user.id)) {
660
- return interaction.reply({ content: "Only developers can use this command.", ephemeral: true });
661
- }
662
- if (command2.guildOnly && !interaction.inGuild()) {
663
- return interaction.reply({ content: "This command can only be used in a server.", ephemeral: true });
664
- }
665
- if (command2.userPermissions && interaction.memberPermissions) {
666
- const missing = interaction.memberPermissions.missing(command2.userPermissions);
667
- if (missing.length > 0) {
668
- return interaction.reply({ content: `You are missing permissions: \`${missing.join(", ")}\``, ephemeral: true });
669
- }
670
- }
671
- if (command2.botPermissions && interaction.guild?.members.me?.permissions) {
672
- const missing = interaction.guild.members.me.permissions.missing(command2.botPermissions);
673
- if (missing.length > 0) {
674
- return interaction.reply({ content: `I am missing permissions to run this: \`${missing.join(", ")}\``, ephemeral: true });
675
- }
676
- }
677
- if (command2.cooldown) {
678
- if (!this.cooldowns.has(commandKey)) this.cooldowns.set(commandKey, new Collection3());
679
- const now = Date.now();
680
- const timestamps = this.cooldowns.get(commandKey);
681
- const cooldownAmount = command2.cooldown * 1e3;
682
- if (timestamps.has(interaction.user.id)) {
683
- const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;
684
- if (now < expirationTime) {
685
- return interaction.reply({
686
- content: `Please wait, you are on a cooldown. You can use it again <t:${Math.round(expirationTime / 1e3)}:R>.`,
687
- ephemeral: true
688
- });
689
- }
690
- }
691
- timestamps.set(interaction.user.id, now);
692
- setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);
693
- }
725
+ if (!await this.handlePreconditions(command2, interaction, commandKey)) return;
694
726
  try {
695
727
  await command2.execute(interaction, this);
696
728
  } catch (error) {
697
- console.error(`[djs-next] Error executing command: "${commandKey}"`, error);
698
- const msg = { content: "We ran into an internal error executing this command. The developers have been notified.", ephemeral: true };
699
- if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
700
- else await interaction.reply(msg).catch(() => null);
729
+ await this.handleCommandError(error, commandKey, interaction);
701
730
  }
702
731
  }
703
732
  if (interaction.isAutocomplete()) {
@@ -733,28 +762,77 @@ var DJSNextClient = class extends Client {
733
762
  }
734
763
  }
735
764
  if (component) {
765
+ if (!await this.handlePreconditions(component, interaction, interaction.customId)) return;
736
766
  try {
737
767
  await component.execute(interaction, this, params);
738
768
  } catch (error) {
739
- console.error(`[djs-next] Error executing component: "${interaction.customId}"`, error);
740
- const msg = { content: "We ran into an internal error executing this component.", ephemeral: true };
741
- if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
742
- else await interaction.reply(msg).catch(() => null);
769
+ await this.handleCommandError(error, interaction.customId, interaction);
743
770
  }
744
771
  }
745
772
  }
746
773
  });
774
+ this.on("messageCreate", async (message2) => {
775
+ if (message2.author.bot) return;
776
+ if (!this._enableTextCommands) return;
777
+ if (this._middleware) {
778
+ try {
779
+ const shouldContinue = await this._middleware(message2, this);
780
+ if (!shouldContinue) return;
781
+ } catch (error) {
782
+ console.error(`[djs-next] Middleware error (Message):`, error);
783
+ return;
784
+ }
785
+ }
786
+ let content2 = message2.content.trim();
787
+ let matchedPrefix = "";
788
+ let isCommand = false;
789
+ const mentionRegex = new RegExp(`^<@!?${this.user?.id}>\\s*`);
790
+ const canUseMention = this._enableMentionPrefix === true || Array.isArray(this._enableMentionPrefix) && this._enableMentionPrefix.includes(message2.author.id);
791
+ if (canUseMention && mentionRegex.test(content2)) {
792
+ matchedPrefix = content2.match(mentionRegex)[0];
793
+ isCommand = true;
794
+ } else {
795
+ const sortedPrefs = [...this._prefixes].sort((a, b) => b.length - a.length);
796
+ for (const p of sortedPrefs) {
797
+ if (content2.startsWith(p)) {
798
+ matchedPrefix = p;
799
+ isCommand = true;
800
+ break;
801
+ }
802
+ }
803
+ const canUseNoPrefix = this._enableNoPrefix === true || Array.isArray(this._enableNoPrefix) && this._enableNoPrefix.includes(message2.author.id);
804
+ if (!isCommand && canUseNoPrefix) {
805
+ isCommand = true;
806
+ matchedPrefix = "";
807
+ }
808
+ }
809
+ if (!isCommand) return;
810
+ const args2 = content2.slice(matchedPrefix.length).trim().split(/ +/g);
811
+ const commandName = args2.shift()?.toLowerCase();
812
+ if (!commandName) return;
813
+ let command2 = this.commands.get(commandName);
814
+ if (!command2) {
815
+ command2 = this.commands.find((c) => c.aliases?.includes(commandName) || false);
816
+ }
817
+ if (!command2 || !command2.executeText) return;
818
+ if (!await this.handlePreconditions(command2, message2, commandName)) return;
819
+ try {
820
+ await command2.executeText(message2, args2, this);
821
+ } catch (error) {
822
+ await this.handleCommandError(error, commandName, message2);
823
+ }
824
+ });
747
825
  }
748
826
  async start(token) {
749
827
  if (!token) throw new Error("[djs-next] A token must be provided to start the bot.");
750
828
  this.config = await loadConfig();
751
829
  this._guildId = this._guildId || this.config.devGuildId;
752
- if (!this._commandsDir && this.config.directories?.commands) this._commandsDir = path6.resolve(process.cwd(), this.config.directories.commands);
753
- if (!this._eventsDir && this.config.directories?.events) this._eventsDir = path6.resolve(process.cwd(), this.config.directories.events);
754
- if (!this._componentsDir && this.config.directories?.components) this._componentsDir = path6.resolve(process.cwd(), this.config.directories.components);
755
- if (!this._tasksDir && this.config.directories?.tasks) this._tasksDir = path6.resolve(process.cwd(), this.config.directories.tasks);
756
- if (!this._localesDir && this.config.directories?.locales) this._localesDir = path6.resolve(process.cwd(), this.config.directories.locales);
757
- if (this._localesDir) loadLocales(this._localesDir, this.config.defaultLocale);
830
+ if (!this._commandsDir) this._commandsDir = path6.resolve(process.cwd(), this.config.directories?.commands || "src/commands");
831
+ if (!this._eventsDir) this._eventsDir = path6.resolve(process.cwd(), this.config.directories?.events || "src/events");
832
+ if (!this._componentsDir) this._componentsDir = path6.resolve(process.cwd(), this.config.directories?.components || "src/components");
833
+ if (!this._tasksDir) this._tasksDir = path6.resolve(process.cwd(), this.config.directories?.tasks || "src/tasks");
834
+ if (!this._localesDir) this._localesDir = path6.resolve(process.cwd(), this.config.directories?.locales || "src/locales");
835
+ if (fs8.existsSync(this._localesDir)) loadLocales(this._localesDir, this.config.defaultLocale);
758
836
  if (!this._middleware) {
759
837
  const exts = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"];
760
838
  const cwd = process.cwd();
@@ -774,24 +852,24 @@ var DJSNextClient = class extends Client {
774
852
  }
775
853
  }
776
854
  }
777
- if (this._eventsDir) await loadEvents(this, this._eventsDir);
778
- if (this._componentsDir) this.components = await loadComponents(this._componentsDir);
779
- if (this._tasksDir) await loadTasks(this, this._tasksDir);
780
- if (this._commandsDir) {
781
- if (!this._clientId) throw new Error("[djs-next] You must provide a clientId to deploy commands.");
782
- this.commands = await loadAndDeployCommands(this._commandsDir, token, this._clientId, this._guildId);
783
- }
855
+ if (fs8.existsSync(this._eventsDir)) await loadEvents(this, this._eventsDir);
856
+ if (fs8.existsSync(this._componentsDir)) this.components = await loadComponents(this._componentsDir);
857
+ if (fs8.existsSync(this._tasksDir)) await loadTasks(this, this._tasksDir);
784
858
  await this.login(token);
785
859
  console.log(`[djs-next] Bot is ready and logged in as ${this.user?.tag}!`);
860
+ if (fs8.existsSync(this._commandsDir)) {
861
+ this._clientId = this._clientId || this.user.id;
862
+ this.commands = await loadAndDeployCommands(this._commandsDir, token, this._clientId, this._guildId);
863
+ }
786
864
  }
787
- enableDevTools(prefix2 = "dnxt") {
788
- if (prefix2 !== "dnxt" && prefix2 !== "nxt") {
789
- throw new Error(`[djs-next] Developer Tools prefix must be either 'dnxt' or 'nxt'. Received: ${prefix2}`);
865
+ enableDevTools(prefix = "dnxt") {
866
+ if (prefix !== "dnxt" && prefix !== "nxt") {
867
+ throw new Error(`[djs-next] Developer Tools prefix must be either 'dnxt' or 'nxt'. Received: ${prefix}`);
790
868
  }
791
869
  this.on("messageCreate", async (message2) => {
792
- await handleDNXT(message2, this, prefix2);
870
+ await handleDNXT(message2, this, prefix);
793
871
  });
794
- console.log(`[djs-next] \u{1F6E0}\uFE0F Developer Tools enabled. Use "${prefix2}" in chat. Ensure MessageContent intent is enabled!`);
872
+ console.log(`[djs-next] \u{1F6E0}\uFE0F Developer Tools enabled. Use "${prefix}" in chat. Ensure MessageContent intent is enabled!`);
795
873
  }
796
874
  async enableHMR() {
797
875
  try {
@@ -821,6 +899,157 @@ var DJSNextClient = class extends Client {
821
899
  console.warn(`[djs-next] chokidar not installed. HMR is disabled. Please run "npm install chokidar" to use this feature.`);
822
900
  }
823
901
  }
902
+ async handleCommandError(error, commandKey, context) {
903
+ console.error(`[djs-next] Error executing command/component: "${commandKey}"`, error);
904
+ const djs = __require("discord.js");
905
+ if (this.config.responses?.errorBoundary === null) {
906
+ } else {
907
+ try {
908
+ const errorContent = this.config.responses?.errorBoundary || `### \u26A0\uFE0F Execution Error
909
+ > The framework encountered a fatal error while executing \`${commandKey}\`.`;
910
+ const codeBlock = `\`\`\`js
911
+ ${String(error.stack || error.message).substring(0, 1500)}
912
+ \`\`\``;
913
+ if ("commandName" in context || "customId" in context) {
914
+ const container = new djs.ContainerBuilder().setAccentColor(15548997).addTextDisplayComponents(new djs.TextDisplayBuilder().setContent(errorContent)).addSeparatorComponents(new djs.SeparatorBuilder()).addTextDisplayComponents(new djs.TextDisplayBuilder().setContent(codeBlock));
915
+ const payload = { components: [container], flags: 32768, ephemeral: true };
916
+ const i = context;
917
+ if (i.isRepliable()) {
918
+ if (i.replied || i.deferred) await i.followUp(payload);
919
+ else await i.reply(payload);
920
+ }
921
+ } else {
922
+ const embed = new djs.EmbedBuilder().setColor(15548997).setDescription(`${errorContent}
923
+
924
+ ${codeBlock}`);
925
+ const m = context;
926
+ await m.reply({ embeds: [embed] });
927
+ }
928
+ } catch (e) {
929
+ }
930
+ }
931
+ if (this.config.errorLogChannelId) {
932
+ try {
933
+ const channel = await this.channels.fetch(this.config.errorLogChannelId);
934
+ if (channel && channel.isTextBased()) {
935
+ const userId = "user" in context ? context.user.id : context.author.id;
936
+ await channel.send(`\u{1F6A8} **Global Error Boundary Caught Exception**
937
+ **Context:** \`${commandKey}\`
938
+ **User:** <@${userId}>
939
+ \`\`\`js
940
+ ${String(error.stack || error.message).substring(0, 1900)}
941
+ \`\`\``);
942
+ }
943
+ } catch (e) {
944
+ console.error(`[djs-next] Failed to send error to log channel:`, e);
945
+ }
946
+ }
947
+ }
948
+ async handlePreconditions(command2, context, commandKey) {
949
+ const userId = "user" in context ? context.user.id : context.author.id;
950
+ const isGuild = "guild" in context && context.guild !== null;
951
+ const member = context.member;
952
+ const sendErr = async (msg) => {
953
+ if (msg === null) return;
954
+ if ("reply" in context && typeof context.reply === "function") {
955
+ try {
956
+ if ("replied" in context && context.isRepliable() && (context.replied || context.deferred)) {
957
+ await context.followUp({ content: msg, ephemeral: true });
958
+ } else {
959
+ await context.reply({ content: msg, ephemeral: true, allowedMentions: { repliedUser: false } });
960
+ }
961
+ } catch (e) {
962
+ }
963
+ }
964
+ };
965
+ if ("developerOnly" in command2 && command2.developerOnly && !this._developers.includes(userId)) {
966
+ await sendErr(this.config.responses?.developerOnly !== void 0 ? this.config.responses.developerOnly : "Only developers can use this command.");
967
+ return false;
968
+ }
969
+ if ("guildOnly" in command2 && command2.guildOnly && !isGuild) {
970
+ await sendErr(this.config.responses?.guildOnly !== void 0 ? this.config.responses.guildOnly : "This command can only be used in a server.");
971
+ return false;
972
+ }
973
+ if ("userPermissions" in command2 && command2.userPermissions && member?.permissions) {
974
+ const missing = member.permissions.missing(command2.userPermissions);
975
+ if (missing.length > 0) {
976
+ await sendErr(this.config.responses?.missingPerms !== void 0 ? this.config.responses.missingPerms === null ? null : this.config.responses.missingPerms.replace("{perms}", missing.join(", ")) : `You are missing permissions: \`${missing.join(", ")}\``);
977
+ return false;
978
+ }
979
+ }
980
+ if ("botPermissions" in command2 && command2.botPermissions && context.guild?.members.me?.permissions) {
981
+ const missing = context.guild.members.me.permissions.missing(command2.botPermissions);
982
+ if (missing.length > 0) {
983
+ await sendErr(this.config.responses?.missingPerms !== void 0 ? this.config.responses.missingPerms === null ? null : this.config.responses.missingPerms.replace("{perms}", missing.join(", ")) : `I am missing permissions to run this: \`${missing.join(", ")}\``);
984
+ return false;
985
+ }
986
+ }
987
+ let totalCooldown = "cooldown" in command2 && command2.cooldown ? command2.cooldown * 1e3 : 0;
988
+ if (command2.preconditions) {
989
+ for (const pre of command2.preconditions) {
990
+ const parts = pre.split(":");
991
+ const type = parts[0].toLowerCase();
992
+ const val = parts.slice(1).join(":");
993
+ if (type === "owneronly" || type === "developeronly") {
994
+ if (!this._developers.includes(userId)) {
995
+ await sendErr(this.config.responses?.developerOnly !== void 0 ? this.config.responses.developerOnly : "Only developers can use this command.");
996
+ return false;
997
+ }
998
+ } else if (type === "guildonly") {
999
+ if (!isGuild) {
1000
+ await sendErr(this.config.responses?.guildOnly !== void 0 ? this.config.responses.guildOnly : "This command can only be used in a server.");
1001
+ return false;
1002
+ }
1003
+ } else if (type === "requireperms") {
1004
+ const perms = val.split(",").map((p) => p.trim());
1005
+ if (member?.permissions) {
1006
+ const missing = member.permissions.missing(perms);
1007
+ if (missing.length > 0) {
1008
+ await sendErr(this.config.responses?.missingPerms !== void 0 ? this.config.responses.missingPerms === null ? null : this.config.responses.missingPerms.replace("{perms}", missing.join(", ")) : `You are missing permissions: \`${missing.join(", ")}\``);
1009
+ return false;
1010
+ }
1011
+ }
1012
+ } else if (type === "cooldown") {
1013
+ const match = val.match(/(\d+)(s|m|h)/);
1014
+ if (match) {
1015
+ let amount = parseInt(match[1]) * 1e3;
1016
+ if (match[2] === "m") amount *= 60;
1017
+ if (match[2] === "h") amount *= 3600;
1018
+ totalCooldown = Math.max(totalCooldown, amount);
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+ if (totalCooldown > 0) {
1024
+ const now = Date.now();
1025
+ if (this.config.cooldownAdapter) {
1026
+ const lastUsed = await this.config.cooldownAdapter.get(commandKey, userId);
1027
+ if (lastUsed) {
1028
+ const expirationTime = lastUsed + totalCooldown;
1029
+ if (now < expirationTime) {
1030
+ const timeStr = `<t:${Math.round(expirationTime / 1e3)}:R>`;
1031
+ await sendErr(this.config.responses?.cooldown !== void 0 ? this.config.responses.cooldown === null ? null : this.config.responses.cooldown.replace("{time}", timeStr) : `Please wait, you are on a cooldown. You can use it again ${timeStr}.`);
1032
+ return false;
1033
+ }
1034
+ }
1035
+ await this.config.cooldownAdapter.set(commandKey, userId, now);
1036
+ } else {
1037
+ if (!this.cooldowns.has(commandKey)) this.cooldowns.set(commandKey, new Collection3());
1038
+ const timestamps = this.cooldowns.get(commandKey);
1039
+ if (timestamps.has(userId)) {
1040
+ const expirationTime = timestamps.get(userId) + totalCooldown;
1041
+ if (now < expirationTime) {
1042
+ const timeStr = `<t:${Math.round(expirationTime / 1e3)}:R>`;
1043
+ await sendErr(this.config.responses?.cooldown !== void 0 ? this.config.responses.cooldown === null ? null : this.config.responses.cooldown.replace("{time}", timeStr) : `Please wait, you are on a cooldown. You can use it again ${timeStr}.`);
1044
+ return false;
1045
+ }
1046
+ }
1047
+ timestamps.set(userId, now);
1048
+ setTimeout(() => timestamps.delete(userId), totalCooldown);
1049
+ }
1050
+ }
1051
+ return true;
1052
+ }
824
1053
  };
825
1054
 
826
1055
  // src/utils/paginate.ts
@@ -829,23 +1058,38 @@ import {
829
1058
  ButtonBuilder,
830
1059
  ButtonStyle
831
1060
  } from "discord.js";
832
- async function paginate(interaction, pages, time = 6e4) {
833
- if (!interaction.deferred && !interaction.replied) {
834
- await interaction.deferReply();
1061
+ async function paginate(context, pages, time = 6e4) {
1062
+ const isMessage = "author" in context;
1063
+ if (!isMessage) {
1064
+ if (!context.deferred && !context.replied) {
1065
+ await context.deferReply();
1066
+ }
835
1067
  }
836
1068
  if (pages.length === 1) {
837
- return interaction.editReply({ embeds: [pages[0]], components: [] });
1069
+ if (isMessage) {
1070
+ return context.reply({ embeds: [pages[0]], components: [] });
1071
+ } else {
1072
+ return context.editReply({ embeds: [pages[0]], components: [] });
1073
+ }
838
1074
  }
839
1075
  let index = 0;
840
1076
  const prevButton = new ButtonBuilder().setCustomId("djs_prev").setLabel("Previous").setStyle(ButtonStyle.Primary).setDisabled(true);
841
1077
  const nextButton = new ButtonBuilder().setCustomId("djs_next").setLabel("Next").setStyle(ButtonStyle.Primary);
842
1078
  const row = new ActionRowBuilder().addComponents(prevButton, nextButton);
843
- const message2 = await interaction.editReply({
844
- embeds: [pages[index]],
845
- components: [row]
846
- });
1079
+ let message2;
1080
+ if (isMessage) {
1081
+ message2 = await context.reply({
1082
+ embeds: [pages[index]],
1083
+ components: [row]
1084
+ });
1085
+ } else {
1086
+ message2 = await context.editReply({
1087
+ embeds: [pages[index]],
1088
+ components: [row]
1089
+ });
1090
+ }
847
1091
  const collector = message2.createMessageComponentCollector({
848
- filter: (i) => i.user.id === interaction.user.id,
1092
+ filter: (i) => i.user.id === (isMessage ? context.author.id : context.user.id),
849
1093
  time
850
1094
  });
851
1095
  collector.on("collect", async (i) => {
@@ -864,17 +1108,147 @@ async function paginate(interaction, pages, time = 6e4) {
864
1108
  collector.on("end", async () => {
865
1109
  prevButton.setDisabled(true);
866
1110
  nextButton.setDisabled(true);
867
- await interaction.editReply({
868
- components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
869
- }).catch(() => {
870
- });
1111
+ if (message2.editable) {
1112
+ await message2.edit({
1113
+ components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
1114
+ }).catch(() => {
1115
+ });
1116
+ }
871
1117
  });
872
1118
  }
873
1119
 
1120
+ // src/utils/prompts.ts
1121
+ import {
1122
+ ActionRowBuilder as ActionRowBuilder2,
1123
+ ButtonBuilder as ButtonBuilder2,
1124
+ ButtonStyle as ButtonStyle2
1125
+ } from "discord.js";
1126
+ async function confirmPrompt(context, content2, time = 3e4) {
1127
+ const isMessage = "author" in context;
1128
+ if (!isMessage) {
1129
+ if (!context.deferred && !context.replied) {
1130
+ await context.deferReply();
1131
+ }
1132
+ }
1133
+ const yesButton = new ButtonBuilder2().setCustomId("djs_prompt_yes").setLabel("Yes").setStyle(ButtonStyle2.Success);
1134
+ const noButton = new ButtonBuilder2().setCustomId("djs_prompt_no").setLabel("No").setStyle(ButtonStyle2.Danger);
1135
+ const row = new ActionRowBuilder2().addComponents(yesButton, noButton);
1136
+ const payload = { components: [row] };
1137
+ if (typeof content2 === "string") {
1138
+ payload.content = content2;
1139
+ } else {
1140
+ payload.embeds = [content2];
1141
+ }
1142
+ let message2;
1143
+ if (isMessage) {
1144
+ message2 = await context.reply(payload);
1145
+ } else {
1146
+ message2 = await context.editReply(payload);
1147
+ }
1148
+ try {
1149
+ const interaction = await message2.awaitMessageComponent({
1150
+ filter: (i) => i.user.id === (isMessage ? context.author.id : context.user.id),
1151
+ time
1152
+ });
1153
+ if (interaction.customId === "djs_prompt_yes") {
1154
+ await interaction.update({ components: [] });
1155
+ return true;
1156
+ } else {
1157
+ await interaction.update({ components: [] });
1158
+ return false;
1159
+ }
1160
+ } catch (error) {
1161
+ if (message2.editable) {
1162
+ await message2.edit({ components: [] }).catch(() => {
1163
+ });
1164
+ }
1165
+ return null;
1166
+ }
1167
+ }
1168
+
1169
+ // src/utils/PaginationBuilder.ts
1170
+ import {
1171
+ ActionRowBuilder as ActionRowBuilder3,
1172
+ ButtonBuilder as ButtonBuilder3,
1173
+ ButtonStyle as ButtonStyle3,
1174
+ CommandInteraction as CommandInteraction3,
1175
+ ComponentType
1176
+ } from "discord.js";
1177
+ var PaginationBuilder = class {
1178
+ pages = [];
1179
+ timeout = 6e4;
1180
+ constructor(pages) {
1181
+ if (pages) this.pages = pages;
1182
+ }
1183
+ addPage(embed) {
1184
+ this.pages.push(embed);
1185
+ return this;
1186
+ }
1187
+ setPages(pages) {
1188
+ this.pages = pages;
1189
+ return this;
1190
+ }
1191
+ setTimeout(ms) {
1192
+ this.timeout = ms;
1193
+ return this;
1194
+ }
1195
+ async build(target) {
1196
+ if (this.pages.length === 0) throw new Error("[djs-next] PaginationBuilder requires at least one page.");
1197
+ if (this.pages.length === 1) {
1198
+ if (target instanceof CommandInteraction3) {
1199
+ if (target.deferred || target.replied) {
1200
+ return await target.editReply({ embeds: [this.pages[0]] });
1201
+ }
1202
+ return await target.reply({ embeds: [this.pages[0]], fetchReply: true });
1203
+ } else {
1204
+ return await target.reply({ embeds: [this.pages[0]] });
1205
+ }
1206
+ }
1207
+ let currentPage = 0;
1208
+ const row = new ActionRowBuilder3().addComponents(
1209
+ new ButtonBuilder3().setCustomId("prev").setLabel("\u25C0").setStyle(ButtonStyle3.Primary).setDisabled(true),
1210
+ new ButtonBuilder3().setCustomId("page").setLabel(`1 / ${this.pages.length}`).setStyle(ButtonStyle3.Secondary).setDisabled(true),
1211
+ new ButtonBuilder3().setCustomId("next").setLabel("\u25B6").setStyle(ButtonStyle3.Primary)
1212
+ );
1213
+ let replyMsg;
1214
+ if (target instanceof CommandInteraction3) {
1215
+ if (target.deferred || target.replied) {
1216
+ replyMsg = await target.editReply({ embeds: [this.pages[0]], components: [row] });
1217
+ } else {
1218
+ replyMsg = await target.reply({ embeds: [this.pages[0]], components: [row], fetchReply: true });
1219
+ }
1220
+ } else {
1221
+ replyMsg = await target.reply({ embeds: [this.pages[0]], components: [row] });
1222
+ }
1223
+ const userId = target instanceof CommandInteraction3 ? target.user.id : target.author.id;
1224
+ const collector = replyMsg.createMessageComponentCollector({
1225
+ componentType: ComponentType.Button,
1226
+ time: this.timeout,
1227
+ filter: (i) => i.user.id === userId
1228
+ });
1229
+ collector.on("collect", async (i) => {
1230
+ if (i.customId === "prev") currentPage--;
1231
+ else if (i.customId === "next") currentPage++;
1232
+ const newRow = new ActionRowBuilder3().addComponents(
1233
+ new ButtonBuilder3().setCustomId("prev").setLabel("\u25C0").setStyle(ButtonStyle3.Primary).setDisabled(currentPage === 0),
1234
+ new ButtonBuilder3().setCustomId("page").setLabel(`${currentPage + 1} / ${this.pages.length}`).setStyle(ButtonStyle3.Secondary).setDisabled(true),
1235
+ new ButtonBuilder3().setCustomId("next").setLabel("\u25B6").setStyle(ButtonStyle3.Primary).setDisabled(currentPage === this.pages.length - 1)
1236
+ );
1237
+ await i.update({ embeds: [this.pages[currentPage]], components: [newRow] });
1238
+ });
1239
+ collector.on("end", () => {
1240
+ replyMsg.edit({ components: [] }).catch(() => null);
1241
+ });
1242
+ return replyMsg;
1243
+ }
1244
+ };
1245
+
874
1246
  // src/index.ts
875
1247
  export * from "discord.js";
876
1248
  export {
877
1249
  DJSNextClient,
1250
+ PaginationBuilder,
1251
+ confirmPrompt,
878
1252
  defineConfig,
879
1253
  getLocalesCache,
880
1254
  loadConfig,