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/README.md +51 -29
- package/bin/create-djs-next.js +78 -0
- package/dist/index.d.mts +46 -4
- package/dist/index.d.ts +46 -4
- package/dist/index.js +578 -290
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +578 -280
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +213 -106
- package/src/index.ts +4 -1
- package/src/plugins/dnxt.ts +215 -176
- package/src/templates/cjs.ts +11 -6
- package/src/templates/esm.ts +11 -4
- package/src/templates/ts.ts +11 -5
- package/src/types.ts +21 -1
- package/src/utils/PaginationBuilder.ts +94 -0
- package/src/utils/paginate.ts +32 -13
- package/src/utils/prompts.ts +76 -0
- package/test_payload.js +3 -0
- package/test_reply.js +4 -0
- package/tsup.config.ts +1 -1
- package/dist/cli.d.mts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -344
- package/dist/cli.js.map +0 -1
- package/dist/cli.mjs +0 -321
- package/dist/cli.mjs.map +0 -1
- package/src/cli.ts +0 -203
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
|
|
258
|
+
const content2 = fs7.readFileSync(path5.join(localesDir, file), "utf8");
|
|
256
259
|
try {
|
|
257
|
-
localesCache[lang] = JSON.parse(
|
|
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
|
-
|
|
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
|
|
298
|
-
if (
|
|
299
|
-
const
|
|
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
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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, "
|
|
395
|
+
`, evaled, "ansi");
|
|
327
396
|
} catch (err) {
|
|
328
397
|
await sendPaginatedText(message, `\u274C **Evaluation Error**
|
|
329
|
-
`, err.message, "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
`,
|
|
428
|
+
`, resultText, "ansi");
|
|
344
429
|
} catch (err) {
|
|
345
430
|
await sendPaginatedText(message, `\u274C **Shell Error**
|
|
346
|
-
`, err.message, "
|
|
431
|
+
`, err.message, "ansi");
|
|
347
432
|
}
|
|
348
433
|
return;
|
|
349
434
|
}
|
|
350
|
-
if (command === "
|
|
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(
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (
|
|
377
|
-
|
|
378
|
-
|
|
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
|
|
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
|
|
484
|
+
const content2 = fs9.readFileSync(path7.resolve(process.cwd(), file), "utf8");
|
|
394
485
|
await sendPaginatedText(message, `\u{1F4C4} **${file}**
|
|
395
|
-
`,
|
|
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, "
|
|
522
|
+
`, evaled, "ansi");
|
|
467
523
|
} catch (err) {
|
|
468
524
|
await sendPaginatedText(message, `\u274C **Debug Error**
|
|
469
|
-
`, err.message, "
|
|
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: ${
|
|
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
|
|
482
|
-
|
|
483
|
-
|
|
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 === "
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
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 === "
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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 ${
|
|
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,
|
|
565
|
-
const maxLength =
|
|
566
|
-
if (
|
|
567
|
-
await message2.reply(
|
|
568
|
-
|
|
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 <
|
|
574
|
-
chunks.push(
|
|
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
|
|
578
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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 (
|
|
589
|
-
|
|
590
|
-
|
|
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 (
|
|
629
|
+
} else if (i.customId === "next") {
|
|
593
630
|
index = index < chunks.length - 1 ? index + 1 : index;
|
|
594
|
-
} else if (
|
|
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
|
|
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.
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
768
|
-
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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
|
-
|
|
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
|
|
829
|
-
if (!this._eventsDir
|
|
830
|
-
if (!this._componentsDir
|
|
831
|
-
if (!this._tasksDir
|
|
832
|
-
if (!this._localesDir
|
|
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(
|
|
864
|
-
if (
|
|
865
|
-
throw new Error(`[djs-next] Developer Tools prefix must be either 'dnxt' or 'nxt'. Received: ${
|
|
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,
|
|
870
|
+
await handleDNXT(message2, this, prefix);
|
|
869
871
|
});
|
|
870
|
-
console.log(`[djs-next] \u{1F6E0}\uFE0F Developer Tools enabled. Use "${
|
|
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(
|
|
909
|
-
|
|
910
|
-
|
|
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
|
-
|
|
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
|
-
|
|
920
|
-
|
|
921
|
-
|
|
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 ===
|
|
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
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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,
|