djs-next 0.0.1 → 1.0.0-dev.2
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 +29 -51
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +344 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +321 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +4 -46
- package/dist/index.d.ts +4 -46
- package/dist/index.js +290 -578
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +280 -578
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +203 -0
- package/src/client.ts +106 -213
- package/src/index.ts +1 -4
- package/src/plugins/dnxt.ts +176 -215
- package/src/templates/cjs.ts +6 -11
- package/src/templates/esm.ts +4 -11
- package/src/templates/ts.ts +5 -11
- package/src/types.ts +1 -21
- package/src/utils/paginate.ts +13 -32
- package/tsup.config.ts +1 -1
- package/bin/create-djs-next.js +0 -78
- package/src/utils/PaginationBuilder.ts +0 -94
- package/src/utils/prompts.ts +0 -76
- package/test_payload.js +0 -3
- package/test_reply.js +0 -4
package/dist/index.mjs
CHANGED
|
@@ -5,9 +5,6 @@ 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
|
-
|
|
11
8
|
// src/client.ts
|
|
12
9
|
import { Client, Collection as Collection3 } from "discord.js";
|
|
13
10
|
|
|
@@ -255,9 +252,9 @@ function loadLocales(localesDir, defaultLocale) {
|
|
|
255
252
|
for (const file of files) {
|
|
256
253
|
if (file.endsWith(".json")) {
|
|
257
254
|
const lang = file.replace(".json", "");
|
|
258
|
-
const
|
|
255
|
+
const content = fs7.readFileSync(path5.join(localesDir, file), "utf8");
|
|
259
256
|
try {
|
|
260
|
-
localesCache[lang] = JSON.parse(
|
|
257
|
+
localesCache[lang] = JSON.parse(content);
|
|
261
258
|
} catch (e) {
|
|
262
259
|
console.error(`[djs-next] Failed to parse locale file: ${file}`, e);
|
|
263
260
|
}
|
|
@@ -291,92 +288,26 @@ function getLocalesCache() {
|
|
|
291
288
|
}
|
|
292
289
|
|
|
293
290
|
// src/plugins/dnxt.ts
|
|
294
|
-
import { version as djsVersion } from "discord.js";
|
|
295
291
|
import { exec } from "child_process";
|
|
296
292
|
import util from "util";
|
|
297
293
|
import os from "os";
|
|
298
294
|
var execAsync = util.promisify(exec);
|
|
299
|
-
function
|
|
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) {
|
|
295
|
+
async function handleDNXT(message, client, prefix = "dnxt") {
|
|
307
296
|
if (message.author.bot) return;
|
|
308
|
-
if (!client
|
|
309
|
-
if (
|
|
310
|
-
const
|
|
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);
|
|
297
|
+
if (!client["_developers"].includes(message.author.id)) return;
|
|
298
|
+
if (!message.content.startsWith(prefix)) return;
|
|
299
|
+
const args = message.content.slice(prefix.length).trim().split(/ +/);
|
|
327
300
|
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
|
-
}
|
|
355
301
|
if (!command) {
|
|
356
302
|
const mem = process.memoryUsage();
|
|
303
|
+
const discordJsVersion = __require("discord.js/package.json").version;
|
|
357
304
|
const botPing = client.ws.ping;
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
-
});
|
|
305
|
+
const text = `Module was loaded <t:${Math.floor((Date.now() - client.uptime) / 1e3)}:R>.
|
|
306
|
+
DNXT framework plugin, discord.js \`${discordJsVersion}\`, \`Node.js ${process.version}\` on \`${os.type()}\`.
|
|
307
|
+
Latencies: \`${botPing}ms\` websocket ping.
|
|
308
|
+
Memory: \`${(mem.rss / 1024 / 1024).toFixed(2)} MB\` physical, \`${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB\` heap.
|
|
309
|
+
System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2)}\` hrs system uptime.`;
|
|
310
|
+
await message.reply(text);
|
|
380
311
|
return;
|
|
381
312
|
}
|
|
382
313
|
if (command === "js" || command === "eval" || command === "py") {
|
|
@@ -390,12 +321,12 @@ async function handleDNXT(message, client, devPrefix) {
|
|
|
390
321
|
let evaled = await eval(`(async () => { ${code} })()`);
|
|
391
322
|
const end = process.hrtime.bigint();
|
|
392
323
|
const timeMs = Number(end - start) / 1e6;
|
|
393
|
-
if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1
|
|
324
|
+
if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1 });
|
|
394
325
|
await sendPaginatedText(message, `\u2705 **Evaluated in ${timeMs.toFixed(3)}ms**
|
|
395
|
-
`, evaled, "
|
|
326
|
+
`, evaled, "js");
|
|
396
327
|
} catch (err) {
|
|
397
328
|
await sendPaginatedText(message, `\u274C **Evaluation Error**
|
|
398
|
-
`, err.message, "
|
|
329
|
+
`, err.message, "js");
|
|
399
330
|
}
|
|
400
331
|
return;
|
|
401
332
|
}
|
|
@@ -404,74 +335,52 @@ async function handleDNXT(message, client, devPrefix) {
|
|
|
404
335
|
if (!cmd) return void await message.reply("\u274C Please provide a command to execute.");
|
|
405
336
|
try {
|
|
406
337
|
const start2 = process.hrtime.bigint();
|
|
407
|
-
|
|
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
|
-
}
|
|
338
|
+
const { stdout, stderr } = await execAsync(cmd);
|
|
417
339
|
const end2 = process.hrtime.bigint();
|
|
418
340
|
const timeMs2 = Number(end2 - start2) / 1e6;
|
|
419
|
-
|
|
420
|
-
`;
|
|
421
|
-
if (stdout) resultText += `${stdout}
|
|
422
|
-
`;
|
|
423
|
-
if (stderr) resultText += `${stderr}
|
|
424
|
-
`;
|
|
425
|
-
resultText += `
|
|
426
|
-
[status] Return code ${code2}`;
|
|
341
|
+
const result = stdout || stderr || "No output.";
|
|
427
342
|
await sendPaginatedText(message, `\u2705 **Executed in ${timeMs2.toFixed(3)}ms**
|
|
428
|
-
`,
|
|
343
|
+
`, result, "sh");
|
|
429
344
|
} catch (err) {
|
|
430
345
|
await sendPaginatedText(message, `\u274C **Shell Error**
|
|
431
|
-
`, err.message, "
|
|
346
|
+
`, err.message, "sh");
|
|
432
347
|
}
|
|
433
348
|
return;
|
|
434
349
|
}
|
|
435
|
-
if (command === "
|
|
350
|
+
if (command === "reload" || command === "load") {
|
|
436
351
|
const target = args[0]?.toLowerCase();
|
|
437
352
|
try {
|
|
438
353
|
if (target === "commands" && client["_commandsDir"]) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
await message.reply(
|
|
354
|
+
client.commands.clear();
|
|
355
|
+
client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
|
|
356
|
+
await message.reply("\u2705 Reloaded commands.");
|
|
442
357
|
} else if (target === "events" && client["_eventsDir"]) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (command === "load" || command === "reload") await loadEvents(client, client["_eventsDir"]);
|
|
448
|
-
await message.reply(`\u2705 Successfully ${command}ed events.`);
|
|
358
|
+
client.removeAllListeners();
|
|
359
|
+
client["attachCoreListeners"]();
|
|
360
|
+
await loadEvents(client, client["_eventsDir"]);
|
|
361
|
+
await message.reply("\u2705 Reloaded events.");
|
|
449
362
|
} else if (target === "components" && client["_componentsDir"]) {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
await message.reply(
|
|
363
|
+
client.components.clear();
|
|
364
|
+
client.components = await loadComponents(client["_componentsDir"]);
|
|
365
|
+
await message.reply("\u2705 Reloaded components.");
|
|
453
366
|
} else if (target === "locales" && client["_localesDir"]) {
|
|
454
|
-
|
|
455
|
-
await message.reply(
|
|
367
|
+
loadLocales(client["_localesDir"], client.config.defaultLocale);
|
|
368
|
+
await message.reply("\u2705 Reloaded locales.");
|
|
456
369
|
} else if (target === "all" || !target) {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
|
|
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.`);
|
|
370
|
+
client.removeAllListeners();
|
|
371
|
+
client["attachCoreListeners"]();
|
|
372
|
+
client.commands.clear();
|
|
373
|
+
client.components.clear();
|
|
374
|
+
if (client["_eventsDir"]) await loadEvents(client, client["_eventsDir"]);
|
|
375
|
+
if (client["_componentsDir"]) client.components = await loadComponents(client["_componentsDir"]);
|
|
376
|
+
if (client["_localesDir"]) loadLocales(client["_localesDir"], client.config.defaultLocale);
|
|
377
|
+
if (client["_commandsDir"]) client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
|
|
378
|
+
await message.reply("\u2705 Reloaded all framework modules.");
|
|
470
379
|
} else {
|
|
471
380
|
await message.reply("\u274C Unknown target. Valid targets: `commands, events, components, locales, all`");
|
|
472
381
|
}
|
|
473
382
|
} catch (err) {
|
|
474
|
-
await message.reply(`\u274C
|
|
383
|
+
await message.reply(`\u274C **Reload Error:** ${err.message}`);
|
|
475
384
|
}
|
|
476
385
|
return;
|
|
477
386
|
}
|
|
@@ -481,14 +390,49 @@ async function handleDNXT(message, client, devPrefix) {
|
|
|
481
390
|
const file = args.join(" ");
|
|
482
391
|
if (!file) return void await message.reply("\u274C Please provide a file to read.");
|
|
483
392
|
try {
|
|
484
|
-
const
|
|
393
|
+
const content = fs9.readFileSync(path7.resolve(process.cwd(), file), "utf8");
|
|
485
394
|
await sendPaginatedText(message, `\u{1F4C4} **${file}**
|
|
486
|
-
`,
|
|
395
|
+
`, content, file.split(".").pop() || "");
|
|
487
396
|
} catch (e) {
|
|
488
397
|
await message.reply(`\u274C **Error reading file:** ${e.message}`);
|
|
489
398
|
}
|
|
490
399
|
return;
|
|
491
400
|
}
|
|
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
|
+
}
|
|
492
436
|
if (command === "curl") {
|
|
493
437
|
const url = args[0];
|
|
494
438
|
if (!url) return void await message.reply("\u274C Please provide a URL.");
|
|
@@ -516,38 +460,64 @@ async function handleDNXT(message, client, devPrefix) {
|
|
|
516
460
|
const endMem = process.memoryUsage().heapUsed;
|
|
517
461
|
const timeMs = Number(end - start) / 1e6;
|
|
518
462
|
const memDiff = (endMem - startMem) / 1024 / 1024;
|
|
519
|
-
if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1
|
|
463
|
+
if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1 });
|
|
520
464
|
await sendPaginatedText(message, `\u23F1\uFE0F **Debug Execution**
|
|
521
465
|
Time: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`
|
|
522
|
-
`, evaled, "
|
|
466
|
+
`, evaled, "js");
|
|
523
467
|
} catch (err) {
|
|
524
468
|
await sendPaginatedText(message, `\u274C **Debug Error**
|
|
525
|
-
`, err.message, "
|
|
469
|
+
`, err.message, "js");
|
|
526
470
|
}
|
|
527
471
|
return;
|
|
528
472
|
}
|
|
529
473
|
if (command === "in") {
|
|
530
474
|
const channelId = args.shift()?.replace(/<#|>/g, "");
|
|
531
475
|
const cmd = args.join(" ");
|
|
532
|
-
if (!channelId || !cmd) return void await message.reply(`\u274C Usage: ${
|
|
476
|
+
if (!channelId || !cmd) return void await message.reply(`\u274C Usage: ${prefix} in <channel> <command>`);
|
|
533
477
|
try {
|
|
534
478
|
const targetChannel = await client.channels.fetch(channelId);
|
|
535
479
|
if (!targetChannel || !targetChannel.isTextBased()) throw new Error("Invalid Text Channel.");
|
|
536
480
|
const mockMessage = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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 });
|
|
481
|
+
mockMessage.channel = targetChannel;
|
|
482
|
+
mockMessage.channelId = targetChannel.id;
|
|
483
|
+
mockMessage.content = cmd;
|
|
545
484
|
client.emit("messageCreate", mockMessage);
|
|
485
|
+
await message.reply(`\u2705 Redirected execution to <#${targetChannel.id}>.`);
|
|
546
486
|
} catch (e) {
|
|
547
487
|
await message.reply(`\u274C **In Error:** ${e.message}`);
|
|
548
488
|
}
|
|
549
489
|
return;
|
|
550
490
|
}
|
|
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
|
+
}
|
|
551
521
|
if (command === "sync") {
|
|
552
522
|
try {
|
|
553
523
|
await message.reply("\u{1F504} Force syncing slash commands...");
|
|
@@ -558,102 +528,80 @@ Time: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`
|
|
|
558
528
|
}
|
|
559
529
|
return;
|
|
560
530
|
}
|
|
561
|
-
if (command === "
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
531
|
+
if (command === "sql") {
|
|
532
|
+
const query = args.join(" ");
|
|
533
|
+
if (!query) return void await message.reply(`\u274C Usage: ${prefix} sql <query>`);
|
|
534
|
+
try {
|
|
535
|
+
let res;
|
|
536
|
+
if (client.db && typeof client.db.$queryRawUnsafe === "function") {
|
|
537
|
+
res = await client.db.$queryRawUnsafe(query);
|
|
538
|
+
} else if (client.db && typeof client.db.query === "function") {
|
|
539
|
+
res = await client.db.query(query);
|
|
540
|
+
} else {
|
|
541
|
+
return void await message.reply("\u274C Your configured `client.db` does not expose a recognized raw SQL execution method (`$queryRawUnsafe` or `query`).");
|
|
542
|
+
}
|
|
543
|
+
const inspect = util.inspect(res, { depth: 2 });
|
|
544
|
+
await sendPaginatedText(message, `\u{1F5C4}\uFE0F **SQL Query**
|
|
545
|
+
`, inspect, "js");
|
|
546
|
+
} catch (e) {
|
|
547
|
+
await message.reply(`\u274C **SQL Error:** ${e.message}`);
|
|
548
|
+
}
|
|
572
549
|
return;
|
|
573
550
|
}
|
|
574
|
-
if (command === "
|
|
575
|
-
await message.reply("\
|
|
576
|
-
|
|
577
|
-
|
|
551
|
+
if (command === "vc" || command === "voice") {
|
|
552
|
+
if (!message.guild) return void await message.reply("\u274C This command must be used in a server.");
|
|
553
|
+
const me = message.guild.members.me;
|
|
554
|
+
if (!me?.voice?.channel) return void await message.reply("\u274C Bot is not currently in a voice channel.");
|
|
555
|
+
const text = `\u{1F399}\uFE0F **Voice Debugger**
|
|
556
|
+
Channel: <#${me.voice.channel.id}> (\`${me.voice.channel.id}\`)
|
|
557
|
+
Muted: ${me.voice.mute} | Deafened: ${me.voice.deaf}
|
|
558
|
+
Session ID: \`${me.voice.sessionId || "None"}\``;
|
|
559
|
+
await message.reply(text);
|
|
578
560
|
return;
|
|
579
561
|
}
|
|
580
|
-
await message.reply(`\u2753 Unknown ${
|
|
562
|
+
await message.reply(`\u2753 Unknown ${prefix} command. Available: \`js, sh, git, cat, curl, su, in, source, debug, reload, tasks, cancel, sync, sql, vc\``);
|
|
581
563
|
}
|
|
582
|
-
async function sendPaginatedText(message2, header,
|
|
583
|
-
const maxLength =
|
|
584
|
-
if (
|
|
585
|
-
await message2.reply(
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
\`\`\``));
|
|
564
|
+
async function sendPaginatedText(message2, header, content, language = "") {
|
|
565
|
+
const maxLength = 1900;
|
|
566
|
+
if (content.length <= maxLength) {
|
|
567
|
+
await message2.reply(`${header}\`\`\`${language}
|
|
568
|
+
${content}
|
|
569
|
+
\`\`\``);
|
|
589
570
|
return;
|
|
590
571
|
}
|
|
591
572
|
const chunks = [];
|
|
592
|
-
for (let i = 0; i <
|
|
593
|
-
chunks.push(
|
|
573
|
+
for (let i = 0; i < content.length; i += maxLength) {
|
|
574
|
+
chunks.push(content.substring(i, i + maxLength));
|
|
594
575
|
}
|
|
595
576
|
let index = 0;
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
const text = `### ${header.replace(/\\*\\*/g, "")}
|
|
599
|
-
\`\`\`${language}
|
|
600
|
-
${chunks[idx]}
|
|
577
|
+
const reply = await message2.reply(`${header}\`\`\`${language}
|
|
578
|
+
${chunks[index]}
|
|
601
579
|
\`\`\`
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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,
|
|
580
|
+
*Page 1 of ${chunks.length}*`);
|
|
581
|
+
await reply.react("\u25C0\uFE0F");
|
|
582
|
+
await reply.react("\u25B6\uFE0F");
|
|
583
|
+
await reply.react("\u23F9\uFE0F");
|
|
584
|
+
const collector = reply.createReactionCollector({
|
|
585
|
+
filter: (reaction, user) => ["\u25C0\uFE0F", "\u25B6\uFE0F", "\u23F9\uFE0F"].includes(reaction.emoji.name) && user.id === message2.author.id,
|
|
622
586
|
time: 12e4
|
|
623
587
|
});
|
|
624
|
-
collector.on("collect", async (
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
} else if (i.customId === "prev") {
|
|
588
|
+
collector.on("collect", async (reaction, user) => {
|
|
589
|
+
await reaction.users.remove(user.id).catch(() => null);
|
|
590
|
+
if (reaction.emoji.name === "\u25C0\uFE0F") {
|
|
628
591
|
index = index > 0 ? index - 1 : index;
|
|
629
|
-
} else if (
|
|
592
|
+
} else if (reaction.emoji.name === "\u25B6\uFE0F") {
|
|
630
593
|
index = index < chunks.length - 1 ? index + 1 : index;
|
|
631
|
-
} else if (
|
|
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);
|
|
594
|
+
} else if (reaction.emoji.name === "\u23F9\uFE0F") {
|
|
650
595
|
collector.stop();
|
|
651
596
|
return;
|
|
652
597
|
}
|
|
653
|
-
await
|
|
598
|
+
await reply.edit(`${header}\`\`\`${language}
|
|
599
|
+
${chunks[index]}
|
|
600
|
+
\`\`\`
|
|
601
|
+
*Page ${index + 1} of ${chunks.length}*`);
|
|
654
602
|
});
|
|
655
603
|
collector.on("end", () => {
|
|
656
|
-
reply.
|
|
604
|
+
reply.reactions.removeAll().catch(() => null);
|
|
657
605
|
});
|
|
658
606
|
}
|
|
659
607
|
|
|
@@ -675,10 +623,7 @@ var DJSNextClient = class extends Client {
|
|
|
675
623
|
_developers;
|
|
676
624
|
_middleware;
|
|
677
625
|
_prefixes;
|
|
678
|
-
_enableSlashCommands;
|
|
679
|
-
_enableTextCommands;
|
|
680
626
|
_enableMentionPrefix;
|
|
681
|
-
_enableNoPrefix;
|
|
682
627
|
constructor(options) {
|
|
683
628
|
super(options);
|
|
684
629
|
this.commands = new Collection3();
|
|
@@ -694,12 +639,7 @@ var DJSNextClient = class extends Client {
|
|
|
694
639
|
this._middleware = options.middleware;
|
|
695
640
|
const prefs = options.prefixes || [];
|
|
696
641
|
this._prefixes = Array.isArray(prefs) ? prefs : [prefs];
|
|
697
|
-
this._prefixes = this._prefixes.filter((p) => p !== "");
|
|
698
|
-
this._enableSlashCommands = options.enableSlashCommands ?? true;
|
|
699
|
-
this._enableTextCommands = options.enableTextCommands ?? true;
|
|
700
642
|
this._enableMentionPrefix = options.enableMentionPrefix ?? true;
|
|
701
|
-
this._enableNoPrefix = options.enableNoPrefix ?? false;
|
|
702
|
-
if (options.db) this.db = options.db;
|
|
703
643
|
this.attachCoreListeners();
|
|
704
644
|
}
|
|
705
645
|
attachCoreListeners() {
|
|
@@ -714,7 +654,6 @@ var DJSNextClient = class extends Client {
|
|
|
714
654
|
}
|
|
715
655
|
}
|
|
716
656
|
if (interaction.isChatInputCommand()) {
|
|
717
|
-
if (!this._enableSlashCommands) return;
|
|
718
657
|
let commandKey = interaction.commandName;
|
|
719
658
|
const group = interaction.options.getSubcommandGroup(false);
|
|
720
659
|
const sub = interaction.options.getSubcommand(false);
|
|
@@ -722,11 +661,48 @@ var DJSNextClient = class extends Client {
|
|
|
722
661
|
if (sub) commandKey += ` ${sub}`;
|
|
723
662
|
const command2 = this.commands.get(commandKey);
|
|
724
663
|
if (!command2 || !command2.execute) return;
|
|
725
|
-
if (!
|
|
664
|
+
if (command2.developerOnly && !this._developers.includes(interaction.user.id)) {
|
|
665
|
+
return interaction.reply({ content: "Only developers can use this command.", ephemeral: true });
|
|
666
|
+
}
|
|
667
|
+
if (command2.guildOnly && !interaction.inGuild()) {
|
|
668
|
+
return interaction.reply({ content: "This command can only be used in a server.", ephemeral: true });
|
|
669
|
+
}
|
|
670
|
+
if (command2.userPermissions && interaction.memberPermissions) {
|
|
671
|
+
const missing = interaction.memberPermissions.missing(command2.userPermissions);
|
|
672
|
+
if (missing.length > 0) {
|
|
673
|
+
return interaction.reply({ content: `You are missing permissions: \`${missing.join(", ")}\``, ephemeral: true });
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (command2.botPermissions && interaction.guild?.members.me?.permissions) {
|
|
677
|
+
const missing = interaction.guild.members.me.permissions.missing(command2.botPermissions);
|
|
678
|
+
if (missing.length > 0) {
|
|
679
|
+
return interaction.reply({ content: `I am missing permissions to run this: \`${missing.join(", ")}\``, ephemeral: true });
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (command2.cooldown) {
|
|
683
|
+
if (!this.cooldowns.has(commandKey)) this.cooldowns.set(commandKey, new Collection3());
|
|
684
|
+
const now = Date.now();
|
|
685
|
+
const timestamps = this.cooldowns.get(commandKey);
|
|
686
|
+
const cooldownAmount = command2.cooldown * 1e3;
|
|
687
|
+
if (timestamps.has(interaction.user.id)) {
|
|
688
|
+
const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;
|
|
689
|
+
if (now < expirationTime) {
|
|
690
|
+
return interaction.reply({
|
|
691
|
+
content: `Please wait, you are on a cooldown. You can use it again <t:${Math.round(expirationTime / 1e3)}:R>.`,
|
|
692
|
+
ephemeral: true
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
timestamps.set(interaction.user.id, now);
|
|
697
|
+
setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);
|
|
698
|
+
}
|
|
726
699
|
try {
|
|
727
700
|
await command2.execute(interaction, this);
|
|
728
701
|
} catch (error) {
|
|
729
|
-
|
|
702
|
+
console.error(`[djs-next] Error executing command: "${commandKey}"`, error);
|
|
703
|
+
const msg = { content: "We ran into an internal error executing this command. The developers have been notified.", ephemeral: true };
|
|
704
|
+
if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
|
|
705
|
+
else await interaction.reply(msg).catch(() => null);
|
|
730
706
|
}
|
|
731
707
|
}
|
|
732
708
|
if (interaction.isAutocomplete()) {
|
|
@@ -762,18 +738,19 @@ var DJSNextClient = class extends Client {
|
|
|
762
738
|
}
|
|
763
739
|
}
|
|
764
740
|
if (component) {
|
|
765
|
-
if (!await this.handlePreconditions(component, interaction, interaction.customId)) return;
|
|
766
741
|
try {
|
|
767
742
|
await component.execute(interaction, this, params);
|
|
768
743
|
} catch (error) {
|
|
769
|
-
|
|
744
|
+
console.error(`[djs-next] Error executing component: "${interaction.customId}"`, error);
|
|
745
|
+
const msg = { content: "We ran into an internal error executing this component.", ephemeral: true };
|
|
746
|
+
if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
|
|
747
|
+
else await interaction.reply(msg).catch(() => null);
|
|
770
748
|
}
|
|
771
749
|
}
|
|
772
750
|
}
|
|
773
751
|
});
|
|
774
752
|
this.on("messageCreate", async (message2) => {
|
|
775
753
|
if (message2.author.bot) return;
|
|
776
|
-
if (!this._enableTextCommands) return;
|
|
777
754
|
if (this._middleware) {
|
|
778
755
|
try {
|
|
779
756
|
const shouldContinue = await this._middleware(message2, this);
|
|
@@ -783,31 +760,28 @@ var DJSNextClient = class extends Client {
|
|
|
783
760
|
return;
|
|
784
761
|
}
|
|
785
762
|
}
|
|
786
|
-
let
|
|
763
|
+
let content = message2.content.trim();
|
|
787
764
|
let matchedPrefix = "";
|
|
788
765
|
let isCommand = false;
|
|
789
766
|
const mentionRegex = new RegExp(`^<@!?${this.user?.id}>\\s*`);
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
matchedPrefix = content2.match(mentionRegex)[0];
|
|
767
|
+
if (this._enableMentionPrefix && mentionRegex.test(content)) {
|
|
768
|
+
matchedPrefix = content.match(mentionRegex)[0];
|
|
793
769
|
isCommand = true;
|
|
794
770
|
} else {
|
|
795
771
|
const sortedPrefs = [...this._prefixes].sort((a, b) => b.length - a.length);
|
|
772
|
+
if (sortedPrefs.includes("")) {
|
|
773
|
+
isCommand = true;
|
|
774
|
+
}
|
|
796
775
|
for (const p of sortedPrefs) {
|
|
797
|
-
if (
|
|
776
|
+
if (p !== "" && content.startsWith(p)) {
|
|
798
777
|
matchedPrefix = p;
|
|
799
778
|
isCommand = true;
|
|
800
779
|
break;
|
|
801
780
|
}
|
|
802
781
|
}
|
|
803
|
-
const canUseNoPrefix = this._enableNoPrefix === true || Array.isArray(this._enableNoPrefix) && this._enableNoPrefix.includes(message2.author.id);
|
|
804
|
-
if (!isCommand && canUseNoPrefix) {
|
|
805
|
-
isCommand = true;
|
|
806
|
-
matchedPrefix = "";
|
|
807
|
-
}
|
|
808
782
|
}
|
|
809
783
|
if (!isCommand) return;
|
|
810
|
-
const args2 =
|
|
784
|
+
const args2 = content.slice(matchedPrefix.length).trim().split(/ +/g);
|
|
811
785
|
const commandName = args2.shift()?.toLowerCase();
|
|
812
786
|
if (!commandName) return;
|
|
813
787
|
let command2 = this.commands.get(commandName);
|
|
@@ -815,11 +789,35 @@ var DJSNextClient = class extends Client {
|
|
|
815
789
|
command2 = this.commands.find((c) => c.aliases?.includes(commandName) || false);
|
|
816
790
|
}
|
|
817
791
|
if (!command2 || !command2.executeText) return;
|
|
818
|
-
if (!
|
|
792
|
+
if (command2.developerOnly && !this._developers.includes(message2.author.id)) return;
|
|
793
|
+
if (command2.guildOnly && !message2.guild) return;
|
|
794
|
+
if (command2.userPermissions && message2.member?.permissions) {
|
|
795
|
+
const missing = message2.member.permissions.missing(command2.userPermissions);
|
|
796
|
+
if (missing.length > 0) return;
|
|
797
|
+
}
|
|
798
|
+
if (command2.botPermissions && message2.guild?.members.me?.permissions) {
|
|
799
|
+
const missing = message2.guild.members.me.permissions.missing(command2.botPermissions);
|
|
800
|
+
if (missing.length > 0) return;
|
|
801
|
+
}
|
|
802
|
+
if (command2.cooldown) {
|
|
803
|
+
if (!this.cooldowns.has(commandName)) this.cooldowns.set(commandName, new Collection3());
|
|
804
|
+
const now = Date.now();
|
|
805
|
+
const timestamps = this.cooldowns.get(commandName);
|
|
806
|
+
const cooldownAmount = command2.cooldown * 1e3;
|
|
807
|
+
if (timestamps.has(message2.author.id)) {
|
|
808
|
+
const expirationTime = timestamps.get(message2.author.id) + cooldownAmount;
|
|
809
|
+
if (now < expirationTime) {
|
|
810
|
+
return void await message2.reply(`Please wait, you are on a cooldown. You can use it again <t:${Math.round(expirationTime / 1e3)}:R>.`);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
timestamps.set(message2.author.id, now);
|
|
814
|
+
setTimeout(() => timestamps.delete(message2.author.id), cooldownAmount);
|
|
815
|
+
}
|
|
819
816
|
try {
|
|
820
817
|
await command2.executeText(message2, args2, this);
|
|
821
818
|
} catch (error) {
|
|
822
|
-
|
|
819
|
+
console.error(`[djs-next] Error executing text command: "${commandName}"`, error);
|
|
820
|
+
await message2.reply("We ran into an internal error executing this command.").catch(() => null);
|
|
823
821
|
}
|
|
824
822
|
});
|
|
825
823
|
}
|
|
@@ -827,12 +825,12 @@ var DJSNextClient = class extends Client {
|
|
|
827
825
|
if (!token) throw new Error("[djs-next] A token must be provided to start the bot.");
|
|
828
826
|
this.config = await loadConfig();
|
|
829
827
|
this._guildId = this._guildId || this.config.devGuildId;
|
|
830
|
-
if (!this._commandsDir) this._commandsDir = path6.resolve(process.cwd(), this.config.directories
|
|
831
|
-
if (!this._eventsDir) this._eventsDir = path6.resolve(process.cwd(), this.config.directories
|
|
832
|
-
if (!this._componentsDir) this._componentsDir = path6.resolve(process.cwd(), this.config.directories
|
|
833
|
-
if (!this._tasksDir) this._tasksDir = path6.resolve(process.cwd(), this.config.directories
|
|
834
|
-
if (!this._localesDir) this._localesDir = path6.resolve(process.cwd(), this.config.directories
|
|
835
|
-
if (
|
|
828
|
+
if (!this._commandsDir && this.config.directories?.commands) this._commandsDir = path6.resolve(process.cwd(), this.config.directories.commands);
|
|
829
|
+
if (!this._eventsDir && this.config.directories?.events) this._eventsDir = path6.resolve(process.cwd(), this.config.directories.events);
|
|
830
|
+
if (!this._componentsDir && this.config.directories?.components) this._componentsDir = path6.resolve(process.cwd(), this.config.directories.components);
|
|
831
|
+
if (!this._tasksDir && this.config.directories?.tasks) this._tasksDir = path6.resolve(process.cwd(), this.config.directories.tasks);
|
|
832
|
+
if (!this._localesDir && this.config.directories?.locales) this._localesDir = path6.resolve(process.cwd(), this.config.directories.locales);
|
|
833
|
+
if (this._localesDir) loadLocales(this._localesDir, this.config.defaultLocale);
|
|
836
834
|
if (!this._middleware) {
|
|
837
835
|
const exts = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"];
|
|
838
836
|
const cwd = process.cwd();
|
|
@@ -852,24 +850,24 @@ var DJSNextClient = class extends Client {
|
|
|
852
850
|
}
|
|
853
851
|
}
|
|
854
852
|
}
|
|
855
|
-
if (
|
|
856
|
-
if (
|
|
857
|
-
if (
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
if (fs8.existsSync(this._commandsDir)) {
|
|
861
|
-
this._clientId = this._clientId || this.user.id;
|
|
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.");
|
|
862
858
|
this.commands = await loadAndDeployCommands(this._commandsDir, token, this._clientId, this._guildId);
|
|
863
859
|
}
|
|
860
|
+
await this.login(token);
|
|
861
|
+
console.log(`[djs-next] Bot is ready and logged in as ${this.user?.tag}!`);
|
|
864
862
|
}
|
|
865
|
-
enableDevTools(
|
|
866
|
-
if (
|
|
867
|
-
throw new Error(`[djs-next] Developer Tools prefix must be either 'dnxt' or 'nxt'. Received: ${
|
|
863
|
+
enableDevTools(prefix2 = "dnxt") {
|
|
864
|
+
if (prefix2 !== "dnxt" && prefix2 !== "nxt") {
|
|
865
|
+
throw new Error(`[djs-next] Developer Tools prefix must be either 'dnxt' or 'nxt'. Received: ${prefix2}`);
|
|
868
866
|
}
|
|
869
867
|
this.on("messageCreate", async (message2) => {
|
|
870
|
-
await handleDNXT(message2, this,
|
|
868
|
+
await handleDNXT(message2, this, prefix2);
|
|
871
869
|
});
|
|
872
|
-
console.log(`[djs-next] \u{1F6E0}\uFE0F Developer Tools enabled. Use "${
|
|
870
|
+
console.log(`[djs-next] \u{1F6E0}\uFE0F Developer Tools enabled. Use "${prefix2}" in chat. Ensure MessageContent intent is enabled!`);
|
|
873
871
|
}
|
|
874
872
|
async enableHMR() {
|
|
875
873
|
try {
|
|
@@ -899,157 +897,6 @@ var DJSNextClient = class extends Client {
|
|
|
899
897
|
console.warn(`[djs-next] chokidar not installed. HMR is disabled. Please run "npm install chokidar" to use this feature.`);
|
|
900
898
|
}
|
|
901
899
|
}
|
|
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
|
-
}
|
|
1053
900
|
};
|
|
1054
901
|
|
|
1055
902
|
// src/utils/paginate.ts
|
|
@@ -1058,38 +905,23 @@ import {
|
|
|
1058
905
|
ButtonBuilder,
|
|
1059
906
|
ButtonStyle
|
|
1060
907
|
} from "discord.js";
|
|
1061
|
-
async function paginate(
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
if (!context.deferred && !context.replied) {
|
|
1065
|
-
await context.deferReply();
|
|
1066
|
-
}
|
|
908
|
+
async function paginate(interaction, pages, time = 6e4) {
|
|
909
|
+
if (!interaction.deferred && !interaction.replied) {
|
|
910
|
+
await interaction.deferReply();
|
|
1067
911
|
}
|
|
1068
912
|
if (pages.length === 1) {
|
|
1069
|
-
|
|
1070
|
-
return context.reply({ embeds: [pages[0]], components: [] });
|
|
1071
|
-
} else {
|
|
1072
|
-
return context.editReply({ embeds: [pages[0]], components: [] });
|
|
1073
|
-
}
|
|
913
|
+
return interaction.editReply({ embeds: [pages[0]], components: [] });
|
|
1074
914
|
}
|
|
1075
915
|
let index = 0;
|
|
1076
916
|
const prevButton = new ButtonBuilder().setCustomId("djs_prev").setLabel("Previous").setStyle(ButtonStyle.Primary).setDisabled(true);
|
|
1077
917
|
const nextButton = new ButtonBuilder().setCustomId("djs_next").setLabel("Next").setStyle(ButtonStyle.Primary);
|
|
1078
918
|
const row = new ActionRowBuilder().addComponents(prevButton, nextButton);
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
components: [row]
|
|
1084
|
-
});
|
|
1085
|
-
} else {
|
|
1086
|
-
message2 = await context.editReply({
|
|
1087
|
-
embeds: [pages[index]],
|
|
1088
|
-
components: [row]
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
919
|
+
const message2 = await interaction.editReply({
|
|
920
|
+
embeds: [pages[index]],
|
|
921
|
+
components: [row]
|
|
922
|
+
});
|
|
1091
923
|
const collector = message2.createMessageComponentCollector({
|
|
1092
|
-
filter: (i) => i.user.id ===
|
|
924
|
+
filter: (i) => i.user.id === interaction.user.id,
|
|
1093
925
|
time
|
|
1094
926
|
});
|
|
1095
927
|
collector.on("collect", async (i) => {
|
|
@@ -1108,147 +940,17 @@ async function paginate(context, pages, time = 6e4) {
|
|
|
1108
940
|
collector.on("end", async () => {
|
|
1109
941
|
prevButton.setDisabled(true);
|
|
1110
942
|
nextButton.setDisabled(true);
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
}).catch(() => {
|
|
1115
|
-
});
|
|
1116
|
-
}
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
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
|
|
943
|
+
await interaction.editReply({
|
|
944
|
+
components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
|
|
945
|
+
}).catch(() => {
|
|
1152
946
|
});
|
|
1153
|
-
|
|
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
|
-
}
|
|
947
|
+
});
|
|
1167
948
|
}
|
|
1168
949
|
|
|
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
|
-
|
|
1246
950
|
// src/index.ts
|
|
1247
951
|
export * from "discord.js";
|
|
1248
952
|
export {
|
|
1249
953
|
DJSNextClient,
|
|
1250
|
-
PaginationBuilder,
|
|
1251
|
-
confirmPrompt,
|
|
1252
954
|
defineConfig,
|
|
1253
955
|
getLocalesCache,
|
|
1254
956
|
loadConfig,
|