djs-next 1.0.0-dev.1
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 +219 -0
- package/assets/djs-next.png +0 -0
- 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 +109 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +919 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +885 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
- package/src/cli.ts +203 -0
- package/src/client.ts +283 -0
- package/src/handlers/commandHandler.ts +139 -0
- package/src/handlers/componentHandler.ts +31 -0
- package/src/handlers/eventHandler.ts +37 -0
- package/src/handlers/taskHandler.ts +38 -0
- package/src/handlers/utils.ts +25 -0
- package/src/index.ts +7 -0
- package/src/plugins/dnxt.ts +379 -0
- package/src/templates/cjs.ts +49 -0
- package/src/templates/esm.ts +43 -0
- package/src/templates/ts.ts +47 -0
- package/src/test/client.test.ts +8 -0
- package/src/types.ts +69 -0
- package/src/utils/configLoader.ts +27 -0
- package/src/utils/i18n.ts +57 -0
- package/src/utils/paginate.ts +71 -0
- package/tsconfig.json +16 -0
- package/tsup.config.ts +10 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,885 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/client.ts
|
|
9
|
+
import { Client, Collection as Collection3 } from "discord.js";
|
|
10
|
+
|
|
11
|
+
// src/handlers/commandHandler.ts
|
|
12
|
+
import { Collection, REST, Routes } from "discord.js";
|
|
13
|
+
import fs2 from "fs";
|
|
14
|
+
import path2 from "path";
|
|
15
|
+
import { pathToFileURL } from "url";
|
|
16
|
+
|
|
17
|
+
// src/handlers/utils.ts
|
|
18
|
+
import fs from "fs";
|
|
19
|
+
import path from "path";
|
|
20
|
+
function getAllFiles(dirPath, arrayOfFiles = []) {
|
|
21
|
+
const files = fs.readdirSync(dirPath);
|
|
22
|
+
files.forEach((file) => {
|
|
23
|
+
const fullPath = path.join(dirPath, file);
|
|
24
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
25
|
+
arrayOfFiles = getAllFiles(fullPath, arrayOfFiles);
|
|
26
|
+
} else {
|
|
27
|
+
if (file.endsWith(".js") || file.endsWith(".ts") || file.endsWith(".mjs") || file.endsWith(".cjs")) {
|
|
28
|
+
if (!file.endsWith(".d.ts")) {
|
|
29
|
+
arrayOfFiles.push(fullPath);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return arrayOfFiles;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/handlers/commandHandler.ts
|
|
38
|
+
async function loadAndDeployCommands(commandsDir, token, clientId, guildId) {
|
|
39
|
+
const flatCommands = new Collection();
|
|
40
|
+
if (!fs2.existsSync(commandsDir)) {
|
|
41
|
+
console.warn(`[djs-next] Commands directory "${commandsDir}" does not exist.`);
|
|
42
|
+
return flatCommands;
|
|
43
|
+
}
|
|
44
|
+
const commandFiles = getAllFiles(commandsDir);
|
|
45
|
+
const rootNodes = /* @__PURE__ */ new Map();
|
|
46
|
+
function getOrCreateNode(pathParts) {
|
|
47
|
+
let currentMap = rootNodes;
|
|
48
|
+
let currentNode;
|
|
49
|
+
for (const part of pathParts) {
|
|
50
|
+
if (!currentMap.has(part)) {
|
|
51
|
+
currentMap.set(part, {
|
|
52
|
+
name: part,
|
|
53
|
+
description: `${part} command`,
|
|
54
|
+
// Fallback description
|
|
55
|
+
options: [],
|
|
56
|
+
children: /* @__PURE__ */ new Map()
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
currentNode = currentMap.get(part);
|
|
60
|
+
currentMap = currentNode.children;
|
|
61
|
+
}
|
|
62
|
+
return currentNode;
|
|
63
|
+
}
|
|
64
|
+
for (const file of commandFiles) {
|
|
65
|
+
const relativePath = path2.relative(commandsDir, file);
|
|
66
|
+
const parsed = path2.parse(relativePath);
|
|
67
|
+
const dirParts = parsed.dir ? parsed.dir.split(path2.sep) : [];
|
|
68
|
+
const name = parsed.name;
|
|
69
|
+
const pathParts = [...dirParts];
|
|
70
|
+
if (name !== "index") {
|
|
71
|
+
pathParts.push(name);
|
|
72
|
+
}
|
|
73
|
+
if (pathParts.length === 0) continue;
|
|
74
|
+
if (pathParts.length > 3) {
|
|
75
|
+
console.warn(`[djs-next] Command path too deep (Discord allows max 3 levels): ${relativePath}`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const module = await import(pathToFileURL(file).href);
|
|
79
|
+
const commandData = module.default || module.command || module;
|
|
80
|
+
if (commandData) commandData.filepath = file;
|
|
81
|
+
const node = getOrCreateNode(pathParts);
|
|
82
|
+
if (commandData.description) node.description = commandData.description;
|
|
83
|
+
if (commandData.options) node.options = commandData.options;
|
|
84
|
+
if (commandData.execute) {
|
|
85
|
+
node.execute = commandData.execute;
|
|
86
|
+
flatCommands.set(pathParts.join(" "), commandData);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function buildCommandJSON(node, depth) {
|
|
90
|
+
const json = {
|
|
91
|
+
name: node.name,
|
|
92
|
+
description: node.description
|
|
93
|
+
};
|
|
94
|
+
if (node.children.size > 0) {
|
|
95
|
+
json.options = [];
|
|
96
|
+
for (const [_, childNode] of node.children) {
|
|
97
|
+
const childJson = buildCommandJSON(childNode, depth + 1);
|
|
98
|
+
if (depth === 0) {
|
|
99
|
+
childJson.type = childNode.children.size > 0 ? 2 : 1;
|
|
100
|
+
} else if (depth === 1) {
|
|
101
|
+
childJson.type = 1;
|
|
102
|
+
}
|
|
103
|
+
json.options.push(childJson);
|
|
104
|
+
}
|
|
105
|
+
} else if (node.options && node.options.length > 0) {
|
|
106
|
+
json.options = node.options;
|
|
107
|
+
}
|
|
108
|
+
return json;
|
|
109
|
+
}
|
|
110
|
+
const commandsData = Array.from(rootNodes.values()).map((node) => buildCommandJSON(node, 0));
|
|
111
|
+
const rest = new REST({ version: "10" }).setToken(token);
|
|
112
|
+
try {
|
|
113
|
+
console.log(`[djs-next] Started refreshing ${commandsData.length} File-System application (/) commands.`);
|
|
114
|
+
let data;
|
|
115
|
+
if (guildId) {
|
|
116
|
+
data = await rest.put(
|
|
117
|
+
Routes.applicationGuildCommands(clientId, guildId),
|
|
118
|
+
{ body: commandsData }
|
|
119
|
+
);
|
|
120
|
+
} else {
|
|
121
|
+
data = await rest.put(
|
|
122
|
+
Routes.applicationCommands(clientId),
|
|
123
|
+
{ body: commandsData }
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
console.log(`[djs-next] Successfully reloaded ${data.length} File-System application (/) commands.`);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(`[djs-next] Failed to deploy commands:`, error);
|
|
129
|
+
}
|
|
130
|
+
return flatCommands;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/handlers/eventHandler.ts
|
|
134
|
+
import fs3 from "fs";
|
|
135
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
136
|
+
async function loadEvents(client2, eventsDir) {
|
|
137
|
+
if (!fs3.existsSync(eventsDir)) {
|
|
138
|
+
console.warn(`[djs-next] Events directory "${eventsDir}" does not exist.`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const eventFiles = getAllFiles(eventsDir);
|
|
142
|
+
let loadedEvents = 0;
|
|
143
|
+
for (const file of eventFiles) {
|
|
144
|
+
const eventModule = await import(pathToFileURL2(file).href);
|
|
145
|
+
const eventData = eventModule.default?.event || eventModule.event || eventModule.default || eventModule;
|
|
146
|
+
if (eventData) eventData.filepath = file;
|
|
147
|
+
if (!eventData || !eventData.name || !eventData.execute) {
|
|
148
|
+
console.warn(`[djs-next] The event at ${file} is missing a required "name" or "execute" property.`);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (eventData.once) {
|
|
152
|
+
client2.once(eventData.name, (...args2) => eventData.execute(client2, ...args2));
|
|
153
|
+
} else {
|
|
154
|
+
client2.on(eventData.name, (...args2) => eventData.execute(client2, ...args2));
|
|
155
|
+
}
|
|
156
|
+
loadedEvents++;
|
|
157
|
+
}
|
|
158
|
+
if (loadedEvents > 0) {
|
|
159
|
+
console.log(`[djs-next] Successfully loaded ${loadedEvents} events.`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/handlers/componentHandler.ts
|
|
164
|
+
import { Collection as Collection2 } from "discord.js";
|
|
165
|
+
import fs4 from "fs";
|
|
166
|
+
import path3 from "path";
|
|
167
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
168
|
+
async function loadComponents(componentsDir) {
|
|
169
|
+
const components2 = new Collection2();
|
|
170
|
+
if (!fs4.existsSync(componentsDir)) return components2;
|
|
171
|
+
const files = getAllFiles(componentsDir);
|
|
172
|
+
for (const file of files) {
|
|
173
|
+
const module = await import(pathToFileURL3(file).href);
|
|
174
|
+
const componentData = module.default || module.component || module;
|
|
175
|
+
if (componentData) componentData.filepath = file;
|
|
176
|
+
if (!componentData || !componentData.execute) continue;
|
|
177
|
+
const parsed = path3.parse(file);
|
|
178
|
+
const customId = componentData.customId || parsed.name;
|
|
179
|
+
components2.set(customId, componentData);
|
|
180
|
+
}
|
|
181
|
+
console.log(`[djs-next] Successfully loaded ${components2.size} components.`);
|
|
182
|
+
return components2;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/handlers/taskHandler.ts
|
|
186
|
+
import fs5 from "fs";
|
|
187
|
+
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
188
|
+
async function loadTasks(client2, tasksDir) {
|
|
189
|
+
if (!fs5.existsSync(tasksDir)) return;
|
|
190
|
+
const files = getAllFiles(tasksDir);
|
|
191
|
+
let loaded = 0;
|
|
192
|
+
for (const file of files) {
|
|
193
|
+
const module = await import(pathToFileURL4(file).href);
|
|
194
|
+
const taskData = module.default || module.task || module;
|
|
195
|
+
if (taskData) taskData.filepath = file;
|
|
196
|
+
if (!taskData || !taskData.interval || !taskData.execute) continue;
|
|
197
|
+
const intervalId = setInterval(async () => {
|
|
198
|
+
try {
|
|
199
|
+
await taskData.execute(client2);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error(`[djs-next] Background Task error at ${file}:`, error);
|
|
202
|
+
}
|
|
203
|
+
}, taskData.interval);
|
|
204
|
+
if (!client2._activeTasks) client2._activeTasks = /* @__PURE__ */ new Map();
|
|
205
|
+
client2._activeTasks.set(file, intervalId);
|
|
206
|
+
loaded++;
|
|
207
|
+
}
|
|
208
|
+
if (loaded > 0) {
|
|
209
|
+
console.log(`[djs-next] Successfully scheduled ${loaded} background tasks.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/client.ts
|
|
214
|
+
import path6 from "path";
|
|
215
|
+
import fs8 from "fs";
|
|
216
|
+
import { pathToFileURL as pathToFileURL6 } from "url";
|
|
217
|
+
|
|
218
|
+
// src/utils/configLoader.ts
|
|
219
|
+
import path4 from "path";
|
|
220
|
+
import fs6 from "fs";
|
|
221
|
+
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
222
|
+
async function loadConfig() {
|
|
223
|
+
const exts = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"];
|
|
224
|
+
const cwd = process.cwd();
|
|
225
|
+
for (const ext of exts) {
|
|
226
|
+
const configPath = path4.join(cwd, `djs-next.config${ext}`);
|
|
227
|
+
if (fs6.existsSync(configPath)) {
|
|
228
|
+
try {
|
|
229
|
+
const configModule = await import(pathToFileURL5(configPath).href);
|
|
230
|
+
return configModule.default || configModule;
|
|
231
|
+
} catch (err) {
|
|
232
|
+
console.error(`[djs-next] Error loading config file ${configPath}:`, err);
|
|
233
|
+
return {};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return {};
|
|
238
|
+
}
|
|
239
|
+
function defineConfig(config2) {
|
|
240
|
+
return config2;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/utils/i18n.ts
|
|
244
|
+
import fs7 from "fs";
|
|
245
|
+
import path5 from "path";
|
|
246
|
+
var localesCache = {};
|
|
247
|
+
var defaultLoc = "en";
|
|
248
|
+
function loadLocales(localesDir, defaultLocale) {
|
|
249
|
+
if (defaultLocale) defaultLoc = defaultLocale;
|
|
250
|
+
if (!fs7.existsSync(localesDir)) return;
|
|
251
|
+
const files = fs7.readdirSync(localesDir);
|
|
252
|
+
for (const file of files) {
|
|
253
|
+
if (file.endsWith(".json")) {
|
|
254
|
+
const lang = file.replace(".json", "");
|
|
255
|
+
const content = fs7.readFileSync(path5.join(localesDir, file), "utf8");
|
|
256
|
+
try {
|
|
257
|
+
localesCache[lang] = JSON.parse(content);
|
|
258
|
+
} catch (e) {
|
|
259
|
+
console.error(`[djs-next] Failed to parse locale file: ${file}`, e);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function translate(key, locale = defaultLoc, variables) {
|
|
265
|
+
const dict = localesCache[locale] || localesCache[defaultLoc] || {};
|
|
266
|
+
const keys = key.split(".");
|
|
267
|
+
let value = dict;
|
|
268
|
+
for (const k of keys) {
|
|
269
|
+
if (value && typeof value === "object") {
|
|
270
|
+
value = value[k];
|
|
271
|
+
} else {
|
|
272
|
+
value = void 0;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (typeof value !== "string") {
|
|
277
|
+
return key;
|
|
278
|
+
}
|
|
279
|
+
if (variables) {
|
|
280
|
+
for (const [varKey, varValue] of Object.entries(variables)) {
|
|
281
|
+
value = value.replace(new RegExp(`{{s*${varKey}s*}}`, "g"), String(varValue));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return value;
|
|
285
|
+
}
|
|
286
|
+
function getLocalesCache() {
|
|
287
|
+
return localesCache;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/plugins/dnxt.ts
|
|
291
|
+
import { exec } from "child_process";
|
|
292
|
+
import util from "util";
|
|
293
|
+
import os from "os";
|
|
294
|
+
var execAsync = util.promisify(exec);
|
|
295
|
+
async function handleDNXT(message, client, prefix = "dnxt") {
|
|
296
|
+
if (message.author.bot) return;
|
|
297
|
+
if (!client["_developers"].includes(message.author.id)) return;
|
|
298
|
+
if (!message.content.startsWith(prefix)) return;
|
|
299
|
+
const args = message.content.slice(prefix.length).trim().split(/ +/);
|
|
300
|
+
const command = args.shift()?.toLowerCase();
|
|
301
|
+
if (!command) {
|
|
302
|
+
const mem = process.memoryUsage();
|
|
303
|
+
const discordJsVersion = __require("discord.js/package.json").version;
|
|
304
|
+
const botPing = client.ws.ping;
|
|
305
|
+
const text = `Module was loaded <t:${Math.floor((Date.now() - client.uptime) / 1e3)}:R>.
|
|
306
|
+
DNXT framework plugin, discord.js \`${discordJsVersion}\`, \`Node.js ${process.version}\` on \`${os.type()}\`.
|
|
307
|
+
Latencies: \`${botPing}ms\` websocket ping.
|
|
308
|
+
Memory: \`${(mem.rss / 1024 / 1024).toFixed(2)} MB\` physical, \`${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB\` heap.
|
|
309
|
+
System: \`${os.cpus().length}\` thread(s), \`${(os.uptime() / 60 / 60).toFixed(2)}\` hrs system uptime.`;
|
|
310
|
+
await message.reply(text);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (command === "js" || command === "eval" || command === "py") {
|
|
314
|
+
let code = args.join(" ");
|
|
315
|
+
if (code.startsWith("```js") || code.startsWith("```py")) code = code.replace(/^```[a-z]*|```$/g, "");
|
|
316
|
+
else if (code.startsWith("```")) code = code.replace(/^```|```$/g, "");
|
|
317
|
+
if (!code) return void await message.reply("\u274C Please provide code to evaluate.");
|
|
318
|
+
try {
|
|
319
|
+
const start = process.hrtime.bigint();
|
|
320
|
+
const { commands, components, config } = client;
|
|
321
|
+
let evaled = await eval(`(async () => { ${code} })()`);
|
|
322
|
+
const end = process.hrtime.bigint();
|
|
323
|
+
const timeMs = Number(end - start) / 1e6;
|
|
324
|
+
if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1 });
|
|
325
|
+
await sendPaginatedText(message, `\u2705 **Evaluated in ${timeMs.toFixed(3)}ms**
|
|
326
|
+
`, evaled, "js");
|
|
327
|
+
} catch (err) {
|
|
328
|
+
await sendPaginatedText(message, `\u274C **Evaluation Error**
|
|
329
|
+
`, err.message, "js");
|
|
330
|
+
}
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (command === "sh" || command === "shell" || command === "git") {
|
|
334
|
+
const cmd = command === "git" ? "git " + args.join(" ") : args.join(" ");
|
|
335
|
+
if (!cmd) return void await message.reply("\u274C Please provide a command to execute.");
|
|
336
|
+
try {
|
|
337
|
+
const start2 = process.hrtime.bigint();
|
|
338
|
+
const { stdout, stderr } = await execAsync(cmd);
|
|
339
|
+
const end2 = process.hrtime.bigint();
|
|
340
|
+
const timeMs2 = Number(end2 - start2) / 1e6;
|
|
341
|
+
const result = stdout || stderr || "No output.";
|
|
342
|
+
await sendPaginatedText(message, `\u2705 **Executed in ${timeMs2.toFixed(3)}ms**
|
|
343
|
+
`, result, "sh");
|
|
344
|
+
} catch (err) {
|
|
345
|
+
await sendPaginatedText(message, `\u274C **Shell Error**
|
|
346
|
+
`, err.message, "sh");
|
|
347
|
+
}
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (command === "reload" || command === "load") {
|
|
351
|
+
const target = args[0]?.toLowerCase();
|
|
352
|
+
try {
|
|
353
|
+
if (target === "commands" && client["_commandsDir"]) {
|
|
354
|
+
client.commands.clear();
|
|
355
|
+
client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
|
|
356
|
+
await message.reply("\u2705 Reloaded commands.");
|
|
357
|
+
} else if (target === "events" && client["_eventsDir"]) {
|
|
358
|
+
client.removeAllListeners();
|
|
359
|
+
client["attachCoreListeners"]();
|
|
360
|
+
await loadEvents(client, client["_eventsDir"]);
|
|
361
|
+
await message.reply("\u2705 Reloaded events.");
|
|
362
|
+
} else if (target === "components" && client["_componentsDir"]) {
|
|
363
|
+
client.components.clear();
|
|
364
|
+
client.components = await loadComponents(client["_componentsDir"]);
|
|
365
|
+
await message.reply("\u2705 Reloaded components.");
|
|
366
|
+
} else if (target === "locales" && client["_localesDir"]) {
|
|
367
|
+
loadLocales(client["_localesDir"], client.config.defaultLocale);
|
|
368
|
+
await message.reply("\u2705 Reloaded locales.");
|
|
369
|
+
} else if (target === "all" || !target) {
|
|
370
|
+
client.removeAllListeners();
|
|
371
|
+
client["attachCoreListeners"]();
|
|
372
|
+
client.commands.clear();
|
|
373
|
+
client.components.clear();
|
|
374
|
+
if (client["_eventsDir"]) await loadEvents(client, client["_eventsDir"]);
|
|
375
|
+
if (client["_componentsDir"]) client.components = await loadComponents(client["_componentsDir"]);
|
|
376
|
+
if (client["_localesDir"]) loadLocales(client["_localesDir"], client.config.defaultLocale);
|
|
377
|
+
if (client["_commandsDir"]) client.commands = await loadAndDeployCommands(client["_commandsDir"], client.token, client["_clientId"], client["_guildId"]);
|
|
378
|
+
await message.reply("\u2705 Reloaded all framework modules.");
|
|
379
|
+
} else {
|
|
380
|
+
await message.reply("\u274C Unknown target. Valid targets: `commands, events, components, locales, all`");
|
|
381
|
+
}
|
|
382
|
+
} catch (err) {
|
|
383
|
+
await message.reply(`\u274C **Reload Error:** ${err.message}`);
|
|
384
|
+
}
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (command === "cat") {
|
|
388
|
+
const fs9 = await import("fs");
|
|
389
|
+
const path7 = await import("path");
|
|
390
|
+
const file = args.join(" ");
|
|
391
|
+
if (!file) return void await message.reply("\u274C Please provide a file to read.");
|
|
392
|
+
try {
|
|
393
|
+
const content = fs9.readFileSync(path7.resolve(process.cwd(), file), "utf8");
|
|
394
|
+
await sendPaginatedText(message, `\u{1F4C4} **${file}**
|
|
395
|
+
`, content, file.split(".").pop() || "");
|
|
396
|
+
} catch (e) {
|
|
397
|
+
await message.reply(`\u274C **Error reading file:** ${e.message}`);
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
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
|
+
}
|
|
436
|
+
if (command === "curl") {
|
|
437
|
+
const url = args[0];
|
|
438
|
+
if (!url) return void await message.reply("\u274C Please provide a URL.");
|
|
439
|
+
try {
|
|
440
|
+
const res = await fetch(url);
|
|
441
|
+
const text = await res.text();
|
|
442
|
+
await sendPaginatedText(message, `\u{1F310} **Fetched from \`${url}\`**
|
|
443
|
+
`, text, "html");
|
|
444
|
+
} catch (e) {
|
|
445
|
+
await message.reply(`\u274C **Curl Error:** ${e.message}`);
|
|
446
|
+
}
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (command === "debug") {
|
|
450
|
+
let code = args.join(" ");
|
|
451
|
+
if (code.startsWith("```js") || code.startsWith("```py")) code = code.replace(/^```[a-z]*|```$/g, "");
|
|
452
|
+
else if (code.startsWith("```")) code = code.replace(/^```|```$/g, "");
|
|
453
|
+
if (!code) return void await message.reply("\u274C Please provide code to debug.");
|
|
454
|
+
try {
|
|
455
|
+
const startMem = process.memoryUsage().heapUsed;
|
|
456
|
+
const start = process.hrtime.bigint();
|
|
457
|
+
const { commands, components, config } = client;
|
|
458
|
+
let evaled = await eval(`(async () => { ${code} })()`);
|
|
459
|
+
const end = process.hrtime.bigint();
|
|
460
|
+
const endMem = process.memoryUsage().heapUsed;
|
|
461
|
+
const timeMs = Number(end - start) / 1e6;
|
|
462
|
+
const memDiff = (endMem - startMem) / 1024 / 1024;
|
|
463
|
+
if (typeof evaled !== "string") evaled = util.inspect(evaled, { depth: 1 });
|
|
464
|
+
await sendPaginatedText(message, `\u23F1\uFE0F **Debug Execution**
|
|
465
|
+
Time: \`${timeMs.toFixed(3)}ms\` | Heap Delta: \`${memDiff.toFixed(3)}MB\`
|
|
466
|
+
`, evaled, "js");
|
|
467
|
+
} catch (err) {
|
|
468
|
+
await sendPaginatedText(message, `\u274C **Debug Error**
|
|
469
|
+
`, err.message, "js");
|
|
470
|
+
}
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (command === "in") {
|
|
474
|
+
const channelId = args.shift()?.replace(/<#|>/g, "");
|
|
475
|
+
const cmd = args.join(" ");
|
|
476
|
+
if (!channelId || !cmd) return void await message.reply(`\u274C Usage: ${prefix} in <channel> <command>`);
|
|
477
|
+
try {
|
|
478
|
+
const targetChannel = await client.channels.fetch(channelId);
|
|
479
|
+
if (!targetChannel || !targetChannel.isTextBased()) throw new Error("Invalid Text Channel.");
|
|
480
|
+
const mockMessage = Object.assign(Object.create(Object.getPrototypeOf(message)), message);
|
|
481
|
+
mockMessage.channel = targetChannel;
|
|
482
|
+
mockMessage.channelId = targetChannel.id;
|
|
483
|
+
mockMessage.content = cmd;
|
|
484
|
+
client.emit("messageCreate", mockMessage);
|
|
485
|
+
await message.reply(`\u2705 Redirected execution to <#${targetChannel.id}>.`);
|
|
486
|
+
} catch (e) {
|
|
487
|
+
await message.reply(`\u274C **In Error:** ${e.message}`);
|
|
488
|
+
}
|
|
489
|
+
return;
|
|
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
|
+
}
|
|
521
|
+
if (command === "sync") {
|
|
522
|
+
try {
|
|
523
|
+
await message.reply("\u{1F504} Force syncing slash commands...");
|
|
524
|
+
await loadAndDeployCommands(client._commandsDir, client.token, client._clientId, client._guildId);
|
|
525
|
+
await message.reply("\u2705 Slash commands synchronized globally/locally.");
|
|
526
|
+
} catch (e) {
|
|
527
|
+
await message.reply(`\u274C **Sync Error:** ${e.message}`);
|
|
528
|
+
}
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
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
|
+
}
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
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);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
await message.reply(`\u2753 Unknown ${prefix} command. Available: \`js, sh, git, cat, curl, su, in, source, debug, reload, tasks, cancel, sync, sql, vc\``);
|
|
563
|
+
}
|
|
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
|
+
\`\`\``);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const chunks = [];
|
|
573
|
+
for (let i = 0; i < content.length; i += maxLength) {
|
|
574
|
+
chunks.push(content.substring(i, i + maxLength));
|
|
575
|
+
}
|
|
576
|
+
let index = 0;
|
|
577
|
+
const reply = await message2.reply(`${header}\`\`\`${language}
|
|
578
|
+
${chunks[index]}
|
|
579
|
+
\`\`\`
|
|
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,
|
|
586
|
+
time: 12e4
|
|
587
|
+
});
|
|
588
|
+
collector.on("collect", async (reaction, user) => {
|
|
589
|
+
await reaction.users.remove(user.id).catch(() => null);
|
|
590
|
+
if (reaction.emoji.name === "\u25C0\uFE0F") {
|
|
591
|
+
index = index > 0 ? index - 1 : index;
|
|
592
|
+
} else if (reaction.emoji.name === "\u25B6\uFE0F") {
|
|
593
|
+
index = index < chunks.length - 1 ? index + 1 : index;
|
|
594
|
+
} else if (reaction.emoji.name === "\u23F9\uFE0F") {
|
|
595
|
+
collector.stop();
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
await reply.edit(`${header}\`\`\`${language}
|
|
599
|
+
${chunks[index]}
|
|
600
|
+
\`\`\`
|
|
601
|
+
*Page ${index + 1} of ${chunks.length}*`);
|
|
602
|
+
});
|
|
603
|
+
collector.on("end", () => {
|
|
604
|
+
reply.reactions.removeAll().catch(() => null);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// src/client.ts
|
|
609
|
+
var DJSNextClient = class extends Client {
|
|
610
|
+
commands;
|
|
611
|
+
components;
|
|
612
|
+
cooldowns;
|
|
613
|
+
config = {};
|
|
614
|
+
t = translate;
|
|
615
|
+
db;
|
|
616
|
+
_commandsDir;
|
|
617
|
+
_eventsDir;
|
|
618
|
+
_componentsDir;
|
|
619
|
+
_tasksDir;
|
|
620
|
+
_localesDir;
|
|
621
|
+
_clientId;
|
|
622
|
+
_guildId;
|
|
623
|
+
_developers;
|
|
624
|
+
_middleware;
|
|
625
|
+
constructor(options) {
|
|
626
|
+
super(options);
|
|
627
|
+
this.commands = new Collection3();
|
|
628
|
+
this.components = new Collection3();
|
|
629
|
+
this.cooldowns = new Collection3();
|
|
630
|
+
this._commandsDir = options.commandsDir ? path6.resolve(process.cwd(), options.commandsDir) : void 0;
|
|
631
|
+
this._eventsDir = options.eventsDir ? path6.resolve(process.cwd(), options.eventsDir) : void 0;
|
|
632
|
+
this._componentsDir = options.componentsDir ? path6.resolve(process.cwd(), options.componentsDir) : void 0;
|
|
633
|
+
this._tasksDir = options.tasksDir ? path6.resolve(process.cwd(), options.tasksDir) : void 0;
|
|
634
|
+
this._clientId = options.clientId;
|
|
635
|
+
this._guildId = options.guildId;
|
|
636
|
+
this._developers = options.developers || [];
|
|
637
|
+
this._middleware = options.middleware;
|
|
638
|
+
this.attachCoreListeners();
|
|
639
|
+
}
|
|
640
|
+
attachCoreListeners() {
|
|
641
|
+
this.on("interactionCreate", async (interaction) => {
|
|
642
|
+
if (this._middleware) {
|
|
643
|
+
try {
|
|
644
|
+
const shouldContinue = await this._middleware(interaction, this);
|
|
645
|
+
if (!shouldContinue) return;
|
|
646
|
+
} catch (error) {
|
|
647
|
+
console.error(`[djs-next] Middleware error:`, error);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (interaction.isChatInputCommand()) {
|
|
652
|
+
let commandKey = interaction.commandName;
|
|
653
|
+
const group = interaction.options.getSubcommandGroup(false);
|
|
654
|
+
const sub = interaction.options.getSubcommand(false);
|
|
655
|
+
if (group) commandKey += ` ${group}`;
|
|
656
|
+
if (sub) commandKey += ` ${sub}`;
|
|
657
|
+
const command2 = this.commands.get(commandKey);
|
|
658
|
+
if (!command2 || !command2.execute) return;
|
|
659
|
+
if (command2.developerOnly && !this._developers.includes(interaction.user.id)) {
|
|
660
|
+
return interaction.reply({ content: "Only developers can use this command.", ephemeral: true });
|
|
661
|
+
}
|
|
662
|
+
if (command2.guildOnly && !interaction.inGuild()) {
|
|
663
|
+
return interaction.reply({ content: "This command can only be used in a server.", ephemeral: true });
|
|
664
|
+
}
|
|
665
|
+
if (command2.userPermissions && interaction.memberPermissions) {
|
|
666
|
+
const missing = interaction.memberPermissions.missing(command2.userPermissions);
|
|
667
|
+
if (missing.length > 0) {
|
|
668
|
+
return interaction.reply({ content: `You are missing permissions: \`${missing.join(", ")}\``, ephemeral: true });
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (command2.botPermissions && interaction.guild?.members.me?.permissions) {
|
|
672
|
+
const missing = interaction.guild.members.me.permissions.missing(command2.botPermissions);
|
|
673
|
+
if (missing.length > 0) {
|
|
674
|
+
return interaction.reply({ content: `I am missing permissions to run this: \`${missing.join(", ")}\``, ephemeral: true });
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
if (command2.cooldown) {
|
|
678
|
+
if (!this.cooldowns.has(commandKey)) this.cooldowns.set(commandKey, new Collection3());
|
|
679
|
+
const now = Date.now();
|
|
680
|
+
const timestamps = this.cooldowns.get(commandKey);
|
|
681
|
+
const cooldownAmount = command2.cooldown * 1e3;
|
|
682
|
+
if (timestamps.has(interaction.user.id)) {
|
|
683
|
+
const expirationTime = timestamps.get(interaction.user.id) + cooldownAmount;
|
|
684
|
+
if (now < expirationTime) {
|
|
685
|
+
return interaction.reply({
|
|
686
|
+
content: `Please wait, you are on a cooldown. You can use it again <t:${Math.round(expirationTime / 1e3)}:R>.`,
|
|
687
|
+
ephemeral: true
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
timestamps.set(interaction.user.id, now);
|
|
692
|
+
setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);
|
|
693
|
+
}
|
|
694
|
+
try {
|
|
695
|
+
await command2.execute(interaction, this);
|
|
696
|
+
} catch (error) {
|
|
697
|
+
console.error(`[djs-next] Error executing command: "${commandKey}"`, error);
|
|
698
|
+
const msg = { content: "We ran into an internal error executing this command. The developers have been notified.", ephemeral: true };
|
|
699
|
+
if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
|
|
700
|
+
else await interaction.reply(msg).catch(() => null);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (interaction.isAutocomplete()) {
|
|
704
|
+
let commandKey = interaction.commandName;
|
|
705
|
+
const group = interaction.options.getSubcommandGroup(false);
|
|
706
|
+
const sub = interaction.options.getSubcommand(false);
|
|
707
|
+
if (group) commandKey += ` ${group}`;
|
|
708
|
+
if (sub) commandKey += ` ${sub}`;
|
|
709
|
+
const command2 = this.commands.get(commandKey);
|
|
710
|
+
if (command2 && command2.autocomplete) {
|
|
711
|
+
try {
|
|
712
|
+
await command2.autocomplete(interaction, this);
|
|
713
|
+
} catch (error) {
|
|
714
|
+
console.error(`[djs-next] Error executing autocomplete for: "${commandKey}"`, error);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (interaction.isMessageComponent() || interaction.isModalSubmit()) {
|
|
719
|
+
if (interaction.customId === "djs_prev" || interaction.customId === "djs_next") return;
|
|
720
|
+
let component = this.components.get(interaction.customId);
|
|
721
|
+
let params = {};
|
|
722
|
+
if (!component) {
|
|
723
|
+
for (const [key, comp] of this.components) {
|
|
724
|
+
if (!key.includes("[")) continue;
|
|
725
|
+
const escapedKey = key.replace(/[.*+?^${}()|\\-]/g, "\\$&");
|
|
726
|
+
const regexStr = "^" + escapedKey.replace(/\\\[([^\]]+)\\\]/g, "(?<$1>.+)") + "$";
|
|
727
|
+
const match = interaction.customId.match(new RegExp(regexStr));
|
|
728
|
+
if (match) {
|
|
729
|
+
component = comp;
|
|
730
|
+
if (match.groups) params = match.groups;
|
|
731
|
+
break;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if (component) {
|
|
736
|
+
try {
|
|
737
|
+
await component.execute(interaction, this, params);
|
|
738
|
+
} catch (error) {
|
|
739
|
+
console.error(`[djs-next] Error executing component: "${interaction.customId}"`, error);
|
|
740
|
+
const msg = { content: "We ran into an internal error executing this component.", ephemeral: true };
|
|
741
|
+
if (interaction.replied || interaction.deferred) await interaction.followUp(msg).catch(() => null);
|
|
742
|
+
else await interaction.reply(msg).catch(() => null);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
async start(token) {
|
|
749
|
+
if (!token) throw new Error("[djs-next] A token must be provided to start the bot.");
|
|
750
|
+
this.config = await loadConfig();
|
|
751
|
+
this._guildId = this._guildId || this.config.devGuildId;
|
|
752
|
+
if (!this._commandsDir && this.config.directories?.commands) this._commandsDir = path6.resolve(process.cwd(), this.config.directories.commands);
|
|
753
|
+
if (!this._eventsDir && this.config.directories?.events) this._eventsDir = path6.resolve(process.cwd(), this.config.directories.events);
|
|
754
|
+
if (!this._componentsDir && this.config.directories?.components) this._componentsDir = path6.resolve(process.cwd(), this.config.directories.components);
|
|
755
|
+
if (!this._tasksDir && this.config.directories?.tasks) this._tasksDir = path6.resolve(process.cwd(), this.config.directories.tasks);
|
|
756
|
+
if (!this._localesDir && this.config.directories?.locales) this._localesDir = path6.resolve(process.cwd(), this.config.directories.locales);
|
|
757
|
+
if (this._localesDir) loadLocales(this._localesDir, this.config.defaultLocale);
|
|
758
|
+
if (!this._middleware) {
|
|
759
|
+
const exts = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"];
|
|
760
|
+
const cwd = process.cwd();
|
|
761
|
+
for (const ext of exts) {
|
|
762
|
+
const mwPath = path6.join(cwd, `middleware${ext}`);
|
|
763
|
+
if (fs8.existsSync(mwPath)) {
|
|
764
|
+
try {
|
|
765
|
+
const mwModule = await import(pathToFileURL6(mwPath).href);
|
|
766
|
+
this._middleware = mwModule.default?.middleware || mwModule.middleware || mwModule.default || mwModule;
|
|
767
|
+
if (this._middleware) {
|
|
768
|
+
console.log(`[djs-next] Loaded global middleware.`);
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
} catch (err) {
|
|
772
|
+
console.error(`[djs-next] Error loading middleware file ${mwPath}:`, err);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (this._eventsDir) await loadEvents(this, this._eventsDir);
|
|
778
|
+
if (this._componentsDir) this.components = await loadComponents(this._componentsDir);
|
|
779
|
+
if (this._tasksDir) await loadTasks(this, this._tasksDir);
|
|
780
|
+
if (this._commandsDir) {
|
|
781
|
+
if (!this._clientId) throw new Error("[djs-next] You must provide a clientId to deploy commands.");
|
|
782
|
+
this.commands = await loadAndDeployCommands(this._commandsDir, token, this._clientId, this._guildId);
|
|
783
|
+
}
|
|
784
|
+
await this.login(token);
|
|
785
|
+
console.log(`[djs-next] Bot is ready and logged in as ${this.user?.tag}!`);
|
|
786
|
+
}
|
|
787
|
+
enableDevTools(prefix2 = "dnxt") {
|
|
788
|
+
if (prefix2 !== "dnxt" && prefix2 !== "nxt") {
|
|
789
|
+
throw new Error(`[djs-next] Developer Tools prefix must be either 'dnxt' or 'nxt'. Received: ${prefix2}`);
|
|
790
|
+
}
|
|
791
|
+
this.on("messageCreate", async (message2) => {
|
|
792
|
+
await handleDNXT(message2, this, prefix2);
|
|
793
|
+
});
|
|
794
|
+
console.log(`[djs-next] \u{1F6E0}\uFE0F Developer Tools enabled. Use "${prefix2}" in chat. Ensure MessageContent intent is enabled!`);
|
|
795
|
+
}
|
|
796
|
+
async enableHMR() {
|
|
797
|
+
try {
|
|
798
|
+
const chokidar = await import("chokidar");
|
|
799
|
+
console.log(`[djs-next] \u{1F504} HMR Enabled. Watching for file changes...`);
|
|
800
|
+
const watcher = chokidar.watch([
|
|
801
|
+
this._commandsDir,
|
|
802
|
+
this._eventsDir,
|
|
803
|
+
this._componentsDir,
|
|
804
|
+
this._localesDir
|
|
805
|
+
].filter(Boolean), { ignoreInitial: true });
|
|
806
|
+
watcher.on("change", async (filePath) => {
|
|
807
|
+
console.log(`[djs-next] \u267B\uFE0F File changed: ${filePath}. Reloading...`);
|
|
808
|
+
this.removeAllListeners();
|
|
809
|
+
this.commands.clear();
|
|
810
|
+
this.components.clear();
|
|
811
|
+
this.attachCoreListeners();
|
|
812
|
+
if (this._eventsDir) await loadEvents(this, this._eventsDir);
|
|
813
|
+
if (this._componentsDir) this.components = await loadComponents(this._componentsDir);
|
|
814
|
+
if (this._commandsDir && this._clientId) {
|
|
815
|
+
this.commands = await loadAndDeployCommands(this._commandsDir, this.token, this._clientId, this._guildId);
|
|
816
|
+
}
|
|
817
|
+
if (this._localesDir) loadLocales(this._localesDir, this.config.defaultLocale);
|
|
818
|
+
console.log(`[djs-next] \u2705 Hot Reload complete.`);
|
|
819
|
+
});
|
|
820
|
+
} catch (e) {
|
|
821
|
+
console.warn(`[djs-next] chokidar not installed. HMR is disabled. Please run "npm install chokidar" to use this feature.`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// src/utils/paginate.ts
|
|
827
|
+
import {
|
|
828
|
+
ActionRowBuilder,
|
|
829
|
+
ButtonBuilder,
|
|
830
|
+
ButtonStyle
|
|
831
|
+
} from "discord.js";
|
|
832
|
+
async function paginate(interaction, pages, time = 6e4) {
|
|
833
|
+
if (!interaction.deferred && !interaction.replied) {
|
|
834
|
+
await interaction.deferReply();
|
|
835
|
+
}
|
|
836
|
+
if (pages.length === 1) {
|
|
837
|
+
return interaction.editReply({ embeds: [pages[0]], components: [] });
|
|
838
|
+
}
|
|
839
|
+
let index = 0;
|
|
840
|
+
const prevButton = new ButtonBuilder().setCustomId("djs_prev").setLabel("Previous").setStyle(ButtonStyle.Primary).setDisabled(true);
|
|
841
|
+
const nextButton = new ButtonBuilder().setCustomId("djs_next").setLabel("Next").setStyle(ButtonStyle.Primary);
|
|
842
|
+
const row = new ActionRowBuilder().addComponents(prevButton, nextButton);
|
|
843
|
+
const message2 = await interaction.editReply({
|
|
844
|
+
embeds: [pages[index]],
|
|
845
|
+
components: [row]
|
|
846
|
+
});
|
|
847
|
+
const collector = message2.createMessageComponentCollector({
|
|
848
|
+
filter: (i) => i.user.id === interaction.user.id,
|
|
849
|
+
time
|
|
850
|
+
});
|
|
851
|
+
collector.on("collect", async (i) => {
|
|
852
|
+
if (i.customId === "djs_prev") {
|
|
853
|
+
index = index > 0 ? index - 1 : index;
|
|
854
|
+
} else if (i.customId === "djs_next") {
|
|
855
|
+
index = index < pages.length - 1 ? index + 1 : index;
|
|
856
|
+
}
|
|
857
|
+
prevButton.setDisabled(index === 0);
|
|
858
|
+
nextButton.setDisabled(index === pages.length - 1);
|
|
859
|
+
await i.update({
|
|
860
|
+
embeds: [pages[index]],
|
|
861
|
+
components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
|
|
862
|
+
});
|
|
863
|
+
});
|
|
864
|
+
collector.on("end", async () => {
|
|
865
|
+
prevButton.setDisabled(true);
|
|
866
|
+
nextButton.setDisabled(true);
|
|
867
|
+
await interaction.editReply({
|
|
868
|
+
components: [new ActionRowBuilder().addComponents(prevButton, nextButton)]
|
|
869
|
+
}).catch(() => {
|
|
870
|
+
});
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// src/index.ts
|
|
875
|
+
export * from "discord.js";
|
|
876
|
+
export {
|
|
877
|
+
DJSNextClient,
|
|
878
|
+
defineConfig,
|
|
879
|
+
getLocalesCache,
|
|
880
|
+
loadConfig,
|
|
881
|
+
loadLocales,
|
|
882
|
+
paginate,
|
|
883
|
+
translate
|
|
884
|
+
};
|
|
885
|
+
//# sourceMappingURL=index.mjs.map
|