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