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