djs-next 1.0.0-dev.2 → 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
 
@@ -623,7 +675,10 @@ var DJSNextClient = class extends Client {
623
675
  _developers;
624
676
  _middleware;
625
677
  _prefixes;
678
+ _enableSlashCommands;
679
+ _enableTextCommands;
626
680
  _enableMentionPrefix;
681
+ _enableNoPrefix;
627
682
  constructor(options) {
628
683
  super(options);
629
684
  this.commands = new Collection3();
@@ -639,7 +694,12 @@ var DJSNextClient = class extends Client {
639
694
  this._middleware = options.middleware;
640
695
  const prefs = options.prefixes || [];
641
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;
642
700
  this._enableMentionPrefix = options.enableMentionPrefix ?? true;
701
+ this._enableNoPrefix = options.enableNoPrefix ?? false;
702
+ if (options.db) this.db = options.db;
643
703
  this.attachCoreListeners();
644
704
  }
645
705
  attachCoreListeners() {
@@ -654,6 +714,7 @@ var DJSNextClient = class extends Client {
654
714
  }
655
715
  }
656
716
  if (interaction.isChatInputCommand()) {
717
+ if (!this._enableSlashCommands) return;
657
718
  let commandKey = interaction.commandName;
658
719
  const group = interaction.options.getSubcommandGroup(false);
659
720
  const sub = interaction.options.getSubcommand(false);
@@ -661,48 +722,11 @@ var DJSNextClient = class extends Client {
661
722
  if (sub) commandKey += ` ${sub}`;
662
723
  const command2 = this.commands.get(commandKey);
663
724
  if (!command2 || !command2.execute) return;
664
- if (command2.developerOnly && !this._developers.includes(interaction.user.id)) {
665
- return interaction.reply({ content: "Only developers can use this command.", ephemeral: true });
666
- }
667
- if (command2.guildOnly && !interaction.inGuild()) {
668
- return interaction.reply({ content: "This command can only be used in a server.", ephemeral: true });
669
- }
670
- if (command2.userPermissions && interaction.memberPermissions) {
671
- const missing = interaction.memberPermissions.missing(command2.userPermissions);
672
- if (missing.length > 0) {
673
- return interaction.reply({ content: `You are missing permissions: \`${missing.join(", ")}\``, ephemeral: true });
674
- }
675
- }
676
- if (command2.botPermissions && interaction.guild?.members.me?.permissions) {
677
- const missing = interaction.guild.members.me.permissions.missing(command2.botPermissions);
678
- if (missing.length > 0) {
679
- return interaction.reply({ content: `I am missing permissions to run this: \`${missing.join(", ")}\``, ephemeral: true });
680
- }
681
- }
682
- if (command2.cooldown) {
683
- if (!this.cooldowns.has(commandKey)) this.cooldowns.set(commandKey, new Collection3());
684
- const now = Date.now();
685
- const timestamps = this.cooldowns.get(commandKey);
686
- const cooldownAmount = command2.cooldown * 1e3;
687
- if (timestamps.has(interaction.user.id)) {
688
- const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;
689
- if (now < expirationTime) {
690
- return interaction.reply({
691
- content: `Please wait, you are on a cooldown. You can use it again <t:${Math.round(expirationTime / 1e3)}:R>.`,
692
- ephemeral: true
693
- });
694
- }
695
- }
696
- timestamps.set(interaction.user.id, now);
697
- setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);
698
- }
725
+ if (!await this.handlePreconditions(command2, interaction, commandKey)) return;
699
726
  try {
700
727
  await command2.execute(interaction, this);
701
728
  } catch (error) {
702
- console.error(`[djs-next] Error executing command: "${commandKey}"`, error);
703
- const msg = { content: "We ran into an internal error executing this command. The developers have been notified.", ephemeral: true };
704
- if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
705
- else await interaction.reply(msg).catch(() => null);
729
+ await this.handleCommandError(error, commandKey, interaction);
706
730
  }
707
731
  }
708
732
  if (interaction.isAutocomplete()) {
@@ -738,19 +762,18 @@ var DJSNextClient = class extends Client {
738
762
  }
739
763
  }
740
764
  if (component) {
765
+ if (!await this.handlePreconditions(component, interaction, interaction.customId)) return;
741
766
  try {
742
767
  await component.execute(interaction, this, params);
743
768
  } catch (error) {
744
- console.error(`[djs-next] Error executing component: "${interaction.customId}"`, error);
745
- const msg = { content: "We ran into an internal error executing this component.", ephemeral: true };
746
- if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
747
- else await interaction.reply(msg).catch(() => null);
769
+ await this.handleCommandError(error, interaction.customId, interaction);
748
770
  }
749
771
  }
750
772
  }
751
773
  });
752
774
  this.on("messageCreate", async (message2) => {
753
775
  if (message2.author.bot) return;
776
+ if (!this._enableTextCommands) return;
754
777
  if (this._middleware) {
755
778
  try {
756
779
  const shouldContinue = await this._middleware(message2, this);
@@ -760,28 +783,31 @@ var DJSNextClient = class extends Client {
760
783
  return;
761
784
  }
762
785
  }
763
- let content = message2.content.trim();
786
+ let content2 = message2.content.trim();
764
787
  let matchedPrefix = "";
765
788
  let isCommand = false;
766
789
  const mentionRegex = new RegExp(`^<@!?${this.user?.id}>\\s*`);
767
- if (this._enableMentionPrefix && mentionRegex.test(content)) {
768
- matchedPrefix = content.match(mentionRegex)[0];
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];
769
793
  isCommand = true;
770
794
  } else {
771
795
  const sortedPrefs = [...this._prefixes].sort((a, b) => b.length - a.length);
772
- if (sortedPrefs.includes("")) {
773
- isCommand = true;
774
- }
775
796
  for (const p of sortedPrefs) {
776
- if (p !== "" && content.startsWith(p)) {
797
+ if (content2.startsWith(p)) {
777
798
  matchedPrefix = p;
778
799
  isCommand = true;
779
800
  break;
780
801
  }
781
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
+ }
782
808
  }
783
809
  if (!isCommand) return;
784
- const args2 = content.slice(matchedPrefix.length).trim().split(/ +/g);
810
+ const args2 = content2.slice(matchedPrefix.length).trim().split(/ +/g);
785
811
  const commandName = args2.shift()?.toLowerCase();
786
812
  if (!commandName) return;
787
813
  let command2 = this.commands.get(commandName);
@@ -789,35 +815,11 @@ var DJSNextClient = class extends Client {
789
815
  command2 = this.commands.find((c) => c.aliases?.includes(commandName) || false);
790
816
  }
791
817
  if (!command2 || !command2.executeText) return;
792
- if (command2.developerOnly && !this._developers.includes(message2.author.id)) return;
793
- if (command2.guildOnly && !message2.guild) return;
794
- if (command2.userPermissions && message2.member?.permissions) {
795
- const missing = message2.member.permissions.missing(command2.userPermissions);
796
- if (missing.length > 0) return;
797
- }
798
- if (command2.botPermissions && message2.guild?.members.me?.permissions) {
799
- const missing = message2.guild.members.me.permissions.missing(command2.botPermissions);
800
- if (missing.length > 0) return;
801
- }
802
- if (command2.cooldown) {
803
- if (!this.cooldowns.has(commandName)) this.cooldowns.set(commandName, new Collection3());
804
- const now = Date.now();
805
- const timestamps = this.cooldowns.get(commandName);
806
- const cooldownAmount = command2.cooldown * 1e3;
807
- if (timestamps.has(message2.author.id)) {
808
- const expirationTime = timestamps.get(message2.author.id) + cooldownAmount;
809
- if (now < expirationTime) {
810
- return void await message2.reply(`Please wait, you are on a cooldown. You can use it again <t:${Math.round(expirationTime / 1e3)}:R>.`);
811
- }
812
- }
813
- timestamps.set(message2.author.id, now);
814
- setTimeout(() => timestamps.delete(message2.author.id), cooldownAmount);
815
- }
818
+ if (!await this.handlePreconditions(command2, message2, commandName)) return;
816
819
  try {
817
820
  await command2.executeText(message2, args2, this);
818
821
  } catch (error) {
819
- console.error(`[djs-next] Error executing text command: "${commandName}"`, error);
820
- await message2.reply("We ran into an internal error executing this command.").catch(() => null);
822
+ await this.handleCommandError(error, commandName, message2);
821
823
  }
822
824
  });
823
825
  }
@@ -825,12 +827,12 @@ var DJSNextClient = class extends Client {
825
827
  if (!token) throw new Error("[djs-next] A token must be provided to start the bot.");
826
828
  this.config = await loadConfig();
827
829
  this._guildId = this._guildId || this.config.devGuildId;
828
- if (!this._commandsDir && this.config.directories?.commands) this._commandsDir = path6.resolve(process.cwd(), this.config.directories.commands);
829
- if (!this._eventsDir && this.config.directories?.events) this._eventsDir = path6.resolve(process.cwd(), this.config.directories.events);
830
- if (!this._componentsDir && this.config.directories?.components) this._componentsDir = path6.resolve(process.cwd(), this.config.directories.components);
831
- if (!this._tasksDir && this.config.directories?.tasks) this._tasksDir = path6.resolve(process.cwd(), this.config.directories.tasks);
832
- if (!this._localesDir && this.config.directories?.locales) this._localesDir = path6.resolve(process.cwd(), this.config.directories.locales);
833
- 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);
834
836
  if (!this._middleware) {
835
837
  const exts = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"];
836
838
  const cwd = process.cwd();
@@ -850,24 +852,24 @@ var DJSNextClient = class extends Client {
850
852
  }
851
853
  }
852
854
  }
853
- if (this._eventsDir) await loadEvents(this, this._eventsDir);
854
- if (this._componentsDir) this.components = await loadComponents(this._componentsDir);
855
- if (this._tasksDir) await loadTasks(this, this._tasksDir);
856
- if (this._commandsDir) {
857
- if (!this._clientId) throw new Error("[djs-next] You must provide a clientId to deploy commands.");
858
- this.commands = await loadAndDeployCommands(this._commandsDir, token, this._clientId, this._guildId);
859
- }
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);
860
858
  await this.login(token);
861
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
+ }
862
864
  }
863
- enableDevTools(prefix2 = "dnxt") {
864
- if (prefix2 !== "dnxt" && prefix2 !== "nxt") {
865
- 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}`);
866
868
  }
867
869
  this.on("messageCreate", async (message2) => {
868
- await handleDNXT(message2, this, prefix2);
870
+ await handleDNXT(message2, this, prefix);
869
871
  });
870
- 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!`);
871
873
  }
872
874
  async enableHMR() {
873
875
  try {
@@ -897,6 +899,157 @@ var DJSNextClient = class extends Client {
897
899
  console.warn(`[djs-next] chokidar not installed. HMR is disabled. Please run "npm install chokidar" to use this feature.`);
898
900
  }
899
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
+ }
900
1053
  };
901
1054
 
902
1055
  // src/utils/paginate.ts
@@ -905,23 +1058,38 @@ import {
905
1058
  ButtonBuilder,
906
1059
  ButtonStyle
907
1060
  } from "discord.js";
908
- async function paginate(interaction, pages, time = 6e4) {
909
- if (!interaction.deferred && !interaction.replied) {
910
- 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
+ }
911
1067
  }
912
1068
  if (pages.length === 1) {
913
- 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
+ }
914
1074
  }
915
1075
  let index = 0;
916
1076
  const prevButton = new ButtonBuilder().setCustomId("djs_prev").setLabel("Previous").setStyle(ButtonStyle.Primary).setDisabled(true);
917
1077
  const nextButton = new ButtonBuilder().setCustomId("djs_next").setLabel("Next").setStyle(ButtonStyle.Primary);
918
1078
  const row = new ActionRowBuilder().addComponents(prevButton, nextButton);
919
- const message2 = await interaction.editReply({
920
- embeds: [pages[index]],
921
- components: [row]
922
- });
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
+ }
923
1091
  const collector = message2.createMessageComponentCollector({
924
- filter: (i) => i.user.id === interaction.user.id,
1092
+ filter: (i) => i.user.id === (isMessage ? context.author.id : context.user.id),
925
1093
  time
926
1094
  });
927
1095
  collector.on("collect", async (i) => {
@@ -940,17 +1108,147 @@ async function paginate(interaction, pages, time = 6e4) {
940
1108
  collector.on("end", async () => {
941
1109
  prevButton.setDisabled(true);
942
1110
  nextButton.setDisabled(true);
943
- await interaction.editReply({
944
- components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
945
- }).catch(() => {
946
- });
1111
+ if (message2.editable) {
1112
+ await message2.edit({
1113
+ components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
1114
+ }).catch(() => {
1115
+ });
1116
+ }
947
1117
  });
948
1118
  }
949
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
+
950
1246
  // src/index.ts
951
1247
  export * from "discord.js";
952
1248
  export {
953
1249
  DJSNextClient,
1250
+ PaginationBuilder,
1251
+ confirmPrompt,
954
1252
  defineConfig,
955
1253
  getLocalesCache,
956
1254
  loadConfig,