vimcord 1.0.1 → 1.0.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.
- package/README.md +94 -0
- package/dist/index.cjs +50 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +11 -8
- package/dist/index.d.ts +11 -8
- package/dist/index.js +50 -84
- package/dist/index.js.map +1 -1
- package/dist/metafile-cjs.json +1 -1
- package/dist/metafile-esm.json +1 -1
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# vimcord
|
|
2
|
+
|
|
3
|
+
**Vimcord** (pronounced as in _vhem-cord_) is a lightweight, opinionated framework for **Discord.js**. Built for developers who want to reduce the distance between an idea and a working command without fighting with the library.
|
|
4
|
+
|
|
5
|
+
## 🚀 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install vimcord discord.js
|
|
9
|
+
# or
|
|
10
|
+
pnpm add vimcord discord.js
|
|
11
|
+
# or
|
|
12
|
+
yarn add vimcord discord.js
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 🛠 Quick Start
|
|
16
|
+
|
|
17
|
+
Vimcord uses a `createClient` factory to initialize a pre-configured environment with optional feature flags.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { ActivityType, ClientOptions, GatewayIntentBits } from "discord.js";
|
|
21
|
+
import { createClient, GatewayIntentBits, MongoDatabase, StatusType } from "vimcord";
|
|
22
|
+
|
|
23
|
+
const client = createClient(
|
|
24
|
+
{
|
|
25
|
+
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
useGlobalErrorHandlers: true,
|
|
29
|
+
useDefaultSlashCommandHandler: true,
|
|
30
|
+
useDefaultPrefixCommandHandler: true,
|
|
31
|
+
useDefaultContextCommandHandler: true,
|
|
32
|
+
|
|
33
|
+
// Automatically import the .env using dotEnv
|
|
34
|
+
useEnv: true,
|
|
35
|
+
|
|
36
|
+
// Automatically import event and command modules
|
|
37
|
+
importModules: {
|
|
38
|
+
events: "./events",
|
|
39
|
+
slashCommands: "./commands/slash",
|
|
40
|
+
prefixCommands: "./commands/prefix"
|
|
41
|
+
contextCommands: "./commands/context"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
client.start(async client => {
|
|
47
|
+
// NOTE: This runs *BEFORE* the client logs in
|
|
48
|
+
|
|
49
|
+
// Use Mongo as our database
|
|
50
|
+
await client.useDatabase(new MongoDatabase(client));
|
|
51
|
+
})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 🛠 Features
|
|
55
|
+
|
|
56
|
+
- **CommandManager**: Advanced managers for **Slash**, **Prefix**, and **Context** commands. Includes deep inference for permissions and automated error boundaries.
|
|
57
|
+
- **DatabaseManager**: Seamless **MongoDB/Mongoose** integration via `createMongoSchema` and `useMongoDatabase`.
|
|
58
|
+
- **DiscordTools**: High-level interaction helpers including the **Paginator**, **Prompt**, and **BetterModal** for stateful UI.
|
|
59
|
+
- **DiscordUtils**: Essential Discord-first utilities like `dynaSend`, `fetchMember`, and `isMentionOrSnowflake`.
|
|
60
|
+
- **Logger**: A fun, retro style console logger for clear, actionable terminal output.
|
|
61
|
+
|
|
62
|
+
## 💎 Useful Utilities
|
|
63
|
+
|
|
64
|
+
### **The BetterEmbed & ACF**
|
|
65
|
+
|
|
66
|
+
Stop writing boilerplate for user mentions and avatars. `BetterEmbed` supports **Shorthand Context Formatting (ACF)**, allowing you to use tokens like `$USER` and `$BOT_AVATAR` directly in strings. Vimcord resolves them at runtime.
|
|
67
|
+
|
|
68
|
+
### **The Paginator (Chapters & Nested Pages)**
|
|
69
|
+
|
|
70
|
+
Multi-page embeds shouldn't be a chore. The `Paginator` supports **Chapters**, enabling complex, nested page structures with built-in navigation logic and select menu support.
|
|
71
|
+
|
|
72
|
+
### **The DynaSend: Smart Dispatch**
|
|
73
|
+
|
|
74
|
+
`DynaSend` is an intelligent message delivery system. It automatically detects the interaction state to decide whether to `.reply()`, `.editReply()`, or `.followUp()`. You write one line; Vimcord handles the logic.
|
|
75
|
+
|
|
76
|
+
### **MongoSchemaBuilder: Resilient DB Ops**
|
|
77
|
+
|
|
78
|
+
The `execute` method on your schemas includes built-in **exponential backoff**. If the database is under load or reconnecting, Vimcord retries the operation instead of crashing your command.
|
|
79
|
+
|
|
80
|
+
## 👀 Mentionables
|
|
81
|
+
|
|
82
|
+
- **Strictly Typed**: Full TypeScript support with deep inference for command permissions, events, and database documents.
|
|
83
|
+
- **Feature-Rich**: Includes a built-in CLI, automated status rotation, and sophisticated error boundaries.
|
|
84
|
+
- **Developer-Centric**: Focused on performance and ergonomics.
|
|
85
|
+
|
|
86
|
+
## 👋 About
|
|
87
|
+
|
|
88
|
+
_Vimcord was created by **xsqu1znt**,_ and designed for developers who value performance and aesthetic code.
|
|
89
|
+
|
|
90
|
+
It also takes advantage of my lightweight library [qznt](https://github.com/xsqu1znt/qznt) for a smooth experience.
|
|
91
|
+
|
|
92
|
+
## **_Vimcord is still a work in progress. If you find any bugs, please let me know._**
|
|
93
|
+
|
|
94
|
+
License: MIT
|
package/dist/index.cjs
CHANGED
|
@@ -525,8 +525,8 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
|
|
|
525
525
|
};
|
|
526
526
|
|
|
527
527
|
// src/utils/dir.ts
|
|
528
|
-
var import_jstools = __toESM(require("jstools"));
|
|
529
528
|
var import_node_path = __toESM(require("path"));
|
|
529
|
+
var import_qznt = require("qznt");
|
|
530
530
|
function getProcessDir() {
|
|
531
531
|
const mainPath = process.argv[1];
|
|
532
532
|
if (!mainPath) return "";
|
|
@@ -536,7 +536,7 @@ async function importModulesFromDir(dir, fnPrefix) {
|
|
|
536
536
|
const cwd = getProcessDir();
|
|
537
537
|
const MODULE_RELATIVE_PATH = import_node_path.default.join(cwd, dir);
|
|
538
538
|
const MODULE_LOG_PATH = dir;
|
|
539
|
-
const files =
|
|
539
|
+
const files = import_qznt.$.fs.readDir(MODULE_RELATIVE_PATH).filter(
|
|
540
540
|
(fn) => fn.endsWith(`${fnPrefix ? `.${fnPrefix}` : ""}.js`) || fn.endsWith(`${fnPrefix ? `.${fnPrefix}` : ""}.ts`)
|
|
541
541
|
);
|
|
542
542
|
if (!files.length) {
|
|
@@ -1341,28 +1341,9 @@ function formatThousands(num, sep = ",") {
|
|
|
1341
1341
|
return `${num}`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, sep);
|
|
1342
1342
|
}
|
|
1343
1343
|
|
|
1344
|
-
// src/utils/random.ts
|
|
1345
|
-
function pickRandom(arr, options) {
|
|
1346
|
-
const _rnd = () => {
|
|
1347
|
-
return arr[Math.floor(Math.random() * arr.length)];
|
|
1348
|
-
};
|
|
1349
|
-
let att = 0;
|
|
1350
|
-
let candidate = _rnd();
|
|
1351
|
-
if (options?.notEqualTo !== void 0 && arr.length > 1) {
|
|
1352
|
-
while (candidate === options.notEqualTo) {
|
|
1353
|
-
if (att < (options?.maxRerollAttempts ?? 100)) {
|
|
1354
|
-
throw new Error(`pickRandom reached max reroll attempts (${options?.maxRerollAttempts ?? 100})`);
|
|
1355
|
-
}
|
|
1356
|
-
candidate = _rnd();
|
|
1357
|
-
att++;
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
return options?.clone ? structuredClone(candidate) : candidate;
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
1344
|
// src/modules/status.manager.ts
|
|
1364
|
-
var import_node_cron = __toESM(require("node-cron"));
|
|
1365
1345
|
var import_node_events = __toESM(require("events"));
|
|
1346
|
+
var import_qznt2 = require("qznt");
|
|
1366
1347
|
var VimcordStatusManager = class {
|
|
1367
1348
|
client;
|
|
1368
1349
|
logger;
|
|
@@ -1383,24 +1364,9 @@ var VimcordStatusManager = class {
|
|
|
1383
1364
|
this.logger.debug("Status cleared");
|
|
1384
1365
|
}
|
|
1385
1366
|
});
|
|
1386
|
-
this.emitter.on("rotation", () => {
|
|
1387
|
-
if (this.client.config.app.verbose) {
|
|
1388
|
-
this.logger.debug("Status rotated");
|
|
1389
|
-
}
|
|
1390
|
-
});
|
|
1391
|
-
this.emitter.on("rotationStarted", () => {
|
|
1392
|
-
if (this.client.config.app.verbose) {
|
|
1393
|
-
this.logger.debug("Status rotation resumed \u25B6\uFE0F");
|
|
1394
|
-
}
|
|
1395
|
-
});
|
|
1396
|
-
this.emitter.on("rotationPaused", () => {
|
|
1397
|
-
if (this.client.config.app.verbose) {
|
|
1398
|
-
this.logger.debug("Status rotation paused \u23F8\uFE0F");
|
|
1399
|
-
}
|
|
1400
|
-
});
|
|
1401
1367
|
}
|
|
1402
1368
|
clearData() {
|
|
1403
|
-
this.task?.
|
|
1369
|
+
this.task?.stop();
|
|
1404
1370
|
this.task = null;
|
|
1405
1371
|
this.lastActivity = null;
|
|
1406
1372
|
this.lastActivityIndex = 0;
|
|
@@ -1433,11 +1399,8 @@ var VimcordStatusManager = class {
|
|
|
1433
1399
|
}
|
|
1434
1400
|
async statusRotationTask(clientStatus) {
|
|
1435
1401
|
let activity;
|
|
1436
|
-
if (clientStatus.randomize) {
|
|
1437
|
-
activity =
|
|
1438
|
-
notEqualTo: this.lastActivity,
|
|
1439
|
-
clone: true
|
|
1440
|
-
});
|
|
1402
|
+
if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
|
|
1403
|
+
activity = import_qznt2.$.rnd.choice(clientStatus.activity, { not: this.lastActivity });
|
|
1441
1404
|
this.lastActivity = activity;
|
|
1442
1405
|
} else {
|
|
1443
1406
|
const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
|
|
@@ -1449,34 +1412,22 @@ var VimcordStatusManager = class {
|
|
|
1449
1412
|
}
|
|
1450
1413
|
async scheduleStatusRotation(clientStatus) {
|
|
1451
1414
|
if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
|
|
1452
|
-
this.task?.
|
|
1415
|
+
this.task?.stop();
|
|
1453
1416
|
this.task = null;
|
|
1454
|
-
|
|
1455
|
-
this.task = import_node_cron.default.createTask(
|
|
1456
|
-
`*/${clientStatus.interval} * * * * *`,
|
|
1457
|
-
async () => await this.statusRotationTask(clientStatus),
|
|
1458
|
-
{ noOverlap: true }
|
|
1459
|
-
);
|
|
1417
|
+
this.task = new import_qznt2.$.Loop(() => this.statusRotationTask(clientStatus), import_qznt2.$.math.ms(clientStatus.interval), true);
|
|
1460
1418
|
this.start();
|
|
1461
|
-
this.emitter.emit("rotationStarted", this.task);
|
|
1462
1419
|
}
|
|
1463
1420
|
start() {
|
|
1464
1421
|
if (this.task) {
|
|
1465
1422
|
this.task.start();
|
|
1466
|
-
this.emitter.emit("
|
|
1467
|
-
if (this.client.config.app.verbose) {
|
|
1468
|
-
this.logger.debug("Status rotation started");
|
|
1469
|
-
}
|
|
1423
|
+
this.emitter.emit("started", this.task);
|
|
1470
1424
|
}
|
|
1471
1425
|
return this;
|
|
1472
1426
|
}
|
|
1473
1427
|
pause() {
|
|
1474
1428
|
if (this.task) {
|
|
1475
1429
|
this.task.stop();
|
|
1476
|
-
this.emitter.emit("
|
|
1477
|
-
if (this.client.config.app.verbose) {
|
|
1478
|
-
this.logger.debug("Status rotation paused");
|
|
1479
|
-
}
|
|
1430
|
+
this.emitter.emit("paused", this.task);
|
|
1480
1431
|
}
|
|
1481
1432
|
return this;
|
|
1482
1433
|
}
|
|
@@ -1490,21 +1441,16 @@ var VimcordStatusManager = class {
|
|
|
1490
1441
|
}
|
|
1491
1442
|
if (!clientStatus.interval) {
|
|
1492
1443
|
await this.setActivity(Array.isArray(clientStatus.activity) ? clientStatus.activity[0] : clientStatus.activity);
|
|
1493
|
-
|
|
1494
|
-
}
|
|
1495
|
-
if (clientStatus.interval) {
|
|
1444
|
+
} else {
|
|
1496
1445
|
await this.scheduleStatusRotation(clientStatus);
|
|
1497
1446
|
}
|
|
1498
1447
|
return this;
|
|
1499
1448
|
}
|
|
1500
1449
|
async destroy() {
|
|
1501
1450
|
if (this.task) {
|
|
1502
|
-
this.task.
|
|
1451
|
+
this.task.stop();
|
|
1503
1452
|
this.task = null;
|
|
1504
|
-
this.emitter.emit("
|
|
1505
|
-
if (this.client.config.app.verbose) {
|
|
1506
|
-
this.logger.debug("Status rotation destroyed");
|
|
1507
|
-
}
|
|
1453
|
+
this.emitter.emit("destroyed");
|
|
1508
1454
|
await this.clear();
|
|
1509
1455
|
}
|
|
1510
1456
|
return this;
|
|
@@ -1514,9 +1460,6 @@ var VimcordStatusManager = class {
|
|
|
1514
1460
|
this.clearData();
|
|
1515
1461
|
client.user.setActivity({ name: "" });
|
|
1516
1462
|
this.emitter.emit("cleared");
|
|
1517
|
-
if (this.client.config.app.verbose) {
|
|
1518
|
-
this.logger.debug("Status cleared");
|
|
1519
|
-
}
|
|
1520
1463
|
return this;
|
|
1521
1464
|
}
|
|
1522
1465
|
};
|
|
@@ -3046,7 +2989,7 @@ var BetterCollector = class _BetterCollector {
|
|
|
3046
2989
|
if (shouldBeDeferred.update) {
|
|
3047
2990
|
await interaction.deferUpdate().catch(Boolean);
|
|
3048
2991
|
} else {
|
|
3049
|
-
await interaction.deferReply({
|
|
2992
|
+
await interaction.deferReply({ flags: shouldBeDeferred.ephemeral ? "Ephemeral" : void 0 }).catch(Boolean);
|
|
3050
2993
|
}
|
|
3051
2994
|
} else {
|
|
3052
2995
|
await interaction.deferReply().catch(Boolean);
|
|
@@ -3057,7 +3000,7 @@ var BetterCollector = class _BetterCollector {
|
|
|
3057
3000
|
try {
|
|
3058
3001
|
const isAllowed = await this.validateParticipant(interaction, listener.options?.participants);
|
|
3059
3002
|
if (!isAllowed) return;
|
|
3060
|
-
await listener.fn(interaction);
|
|
3003
|
+
await listener.fn(interaction).finally(() => listener.options?.finally?.(interaction));
|
|
3061
3004
|
} catch (err) {
|
|
3062
3005
|
this.handleListenerError(err);
|
|
3063
3006
|
}
|
|
@@ -3067,7 +3010,7 @@ var BetterCollector = class _BetterCollector {
|
|
|
3067
3010
|
allListeners.map((l) => {
|
|
3068
3011
|
const isAllowed = this.validateParticipant(interaction, l.options?.participants);
|
|
3069
3012
|
if (!isAllowed) return;
|
|
3070
|
-
return l.fn(interaction).catch(this.handleListenerError);
|
|
3013
|
+
return l.fn(interaction).catch(this.handleListenerError).finally(() => l.options?.finally?.(interaction));
|
|
3071
3014
|
})
|
|
3072
3015
|
);
|
|
3073
3016
|
}
|
|
@@ -3917,6 +3860,7 @@ var Prompt = class {
|
|
|
3917
3860
|
content;
|
|
3918
3861
|
embed;
|
|
3919
3862
|
container;
|
|
3863
|
+
textOnly;
|
|
3920
3864
|
buttons;
|
|
3921
3865
|
customButtons;
|
|
3922
3866
|
onResolve;
|
|
@@ -3930,6 +3874,7 @@ var Prompt = class {
|
|
|
3930
3874
|
this.content = options.content;
|
|
3931
3875
|
this.embed = options.embed ?? this.createDefaultForm();
|
|
3932
3876
|
this.container = options?.container;
|
|
3877
|
+
this.textOnly = options.textOnly;
|
|
3933
3878
|
this.buttons = this.createButtons(options.buttons);
|
|
3934
3879
|
this.customButtons = this.createCustomButtons(options.customButtons);
|
|
3935
3880
|
this.onResolve = options.onResolve ?? [3 /* DeleteOnConfirm */, 4 /* DeleteOnReject */];
|
|
@@ -4009,7 +3954,7 @@ var Prompt = class {
|
|
|
4009
3954
|
}
|
|
4010
3955
|
buildSendOptions(options) {
|
|
4011
3956
|
const sendData = { ...options };
|
|
4012
|
-
if (this.container) {
|
|
3957
|
+
if (!this.textOnly && this.container) {
|
|
4013
3958
|
sendData.components = Array.isArray(sendData.components) ? [...sendData.components, this.container] : [this.container];
|
|
4014
3959
|
const existingFlags = sendData.flags ? Array.isArray(sendData.flags) ? sendData.flags : [sendData.flags] : [];
|
|
4015
3960
|
if (!existingFlags.includes("IsComponentsV2")) {
|
|
@@ -4018,7 +3963,9 @@ var Prompt = class {
|
|
|
4018
3963
|
sendData.flags = existingFlags;
|
|
4019
3964
|
}
|
|
4020
3965
|
} else {
|
|
4021
|
-
|
|
3966
|
+
if (!this.textOnly) {
|
|
3967
|
+
sendData.embeds = Array.isArray(sendData.embeds) ? [this.embed, ...sendData.embeds] : [this.embed];
|
|
3968
|
+
}
|
|
4022
3969
|
}
|
|
4023
3970
|
if (this.content) {
|
|
4024
3971
|
sendData.content = this.content;
|
|
@@ -4104,7 +4051,7 @@ async function prompt(handler, options, sendOptions) {
|
|
|
4104
4051
|
|
|
4105
4052
|
// src/utils/VimcordCLI.ts
|
|
4106
4053
|
var import_node_readline = require("readline");
|
|
4107
|
-
var
|
|
4054
|
+
var import_qznt3 = require("qznt");
|
|
4108
4055
|
var VimcordCLI = class {
|
|
4109
4056
|
rl;
|
|
4110
4057
|
options;
|
|
@@ -4143,7 +4090,7 @@ var VimcordCLI = class {
|
|
|
4143
4090
|
return { isCommand: true, commandName, content: args.join(" "), args };
|
|
4144
4091
|
}
|
|
4145
4092
|
getClientInstance(line) {
|
|
4146
|
-
const clientIndex =
|
|
4093
|
+
const clientIndex = import_qznt3.$.str.getFlag(line, "--client", 1) || import_qznt3.$.str.getFlag(line, "-c", 1);
|
|
4147
4094
|
if (clientIndex) {
|
|
4148
4095
|
const idx = Number(clientIndex);
|
|
4149
4096
|
if (isNaN(idx)) {
|
|
@@ -4193,7 +4140,7 @@ CLI.addCommand("register", "Register app commands (slash & context) globally, or
|
|
|
4193
4140
|
if (!["guild", "global"].includes(mode)) {
|
|
4194
4141
|
return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
|
|
4195
4142
|
}
|
|
4196
|
-
let guildIds = (
|
|
4143
|
+
let guildIds = (import_qznt3.$.str.getFlag(content, "--guilds", 1) || import_qznt3.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
|
|
4197
4144
|
if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
|
|
4198
4145
|
switch (mode) {
|
|
4199
4146
|
case "guild":
|
|
@@ -4215,7 +4162,7 @@ CLI.addCommand("unregister", "Unregister app commands globally, or per guild", a
|
|
|
4215
4162
|
if (!["guild", "global"].includes(mode)) {
|
|
4216
4163
|
return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
|
|
4217
4164
|
}
|
|
4218
|
-
let guildIds = (
|
|
4165
|
+
let guildIds = (import_qznt3.$.str.getFlag(content, "--guilds", 1) || import_qznt3.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
|
|
4219
4166
|
if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
|
|
4220
4167
|
switch (mode) {
|
|
4221
4168
|
case "guild":
|
|
@@ -4234,9 +4181,9 @@ CLI.addCommand("stats", "View statistics about a client instance", (args, conten
|
|
|
4234
4181
|
const client = CLI.getClientInstance(content);
|
|
4235
4182
|
if (!client) return;
|
|
4236
4183
|
CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
|
|
4237
|
-
"Guilds:":
|
|
4184
|
+
"Guilds:": import_qznt3.$.format.number(client.guilds.cache.size),
|
|
4238
4185
|
"Ping:": `${client.ws.ping || 0}ms`,
|
|
4239
|
-
"Uptime:": `${
|
|
4186
|
+
"Uptime:": `${import_qznt3.$.math.secs(client.uptime || 0)}s`,
|
|
4240
4187
|
"Process Uptime:": `${Math.floor(process.uptime())}s`,
|
|
4241
4188
|
"Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
|
|
4242
4189
|
});
|
|
@@ -4253,7 +4200,7 @@ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
|
|
|
4253
4200
|
for (const cmd of commands) {
|
|
4254
4201
|
tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
|
|
4255
4202
|
}
|
|
4256
|
-
return CLI.logger.table(`(cmds) ~ slash (${
|
|
4203
|
+
return CLI.logger.table(`(cmds) ~ slash (${import_qznt3.$.format.number(commands.length)})`, tableData);
|
|
4257
4204
|
}
|
|
4258
4205
|
case "prefix": {
|
|
4259
4206
|
const commands = Array.from(client.commands.prefix.commands.values());
|
|
@@ -4269,7 +4216,7 @@ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
|
|
|
4269
4216
|
const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
|
|
4270
4217
|
tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
|
|
4271
4218
|
}
|
|
4272
|
-
return CLI.logger.table(`(cmds) ~ prefix (${
|
|
4219
|
+
return CLI.logger.table(`(cmds) ~ prefix (${import_qznt3.$.format.number(commands.length)})`, tableData);
|
|
4273
4220
|
}
|
|
4274
4221
|
case "ctx": {
|
|
4275
4222
|
const commands = Array.from(client.commands.context.commands.values());
|
|
@@ -4279,7 +4226,7 @@ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
|
|
|
4279
4226
|
const type = cmd.builder.type === 2 ? "User" : "Msg";
|
|
4280
4227
|
tableData[`[${type}] ${cmd.builder.name}`] = "";
|
|
4281
4228
|
}
|
|
4282
|
-
return CLI.logger.table(`(cmds) ~ ctx (${
|
|
4229
|
+
return CLI.logger.table(`(cmds) ~ ctx (${import_qznt3.$.format.number(commands.length)})`, tableData);
|
|
4283
4230
|
}
|
|
4284
4231
|
default:
|
|
4285
4232
|
return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
|
|
@@ -4306,6 +4253,25 @@ function createClient(options, features = {}, config = {}) {
|
|
|
4306
4253
|
function getClientInstances() {
|
|
4307
4254
|
return clientInstances;
|
|
4308
4255
|
}
|
|
4256
|
+
|
|
4257
|
+
// src/utils/random.ts
|
|
4258
|
+
function pickRandom(arr, options) {
|
|
4259
|
+
const _rnd = () => {
|
|
4260
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
4261
|
+
};
|
|
4262
|
+
let att = 0;
|
|
4263
|
+
let candidate = _rnd();
|
|
4264
|
+
if (options?.notEqualTo !== void 0 && arr.length > 1) {
|
|
4265
|
+
while (candidate === options.notEqualTo) {
|
|
4266
|
+
if (att < (options?.maxRerollAttempts ?? 100)) {
|
|
4267
|
+
throw new Error(`pickRandom reached max reroll attempts (${options?.maxRerollAttempts ?? 100})`);
|
|
4268
|
+
}
|
|
4269
|
+
candidate = _rnd();
|
|
4270
|
+
att++;
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
return options?.clone ? structuredClone(candidate) : candidate;
|
|
4274
|
+
}
|
|
4309
4275
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4310
4276
|
0 && (module.exports = {
|
|
4311
4277
|
BaseCommandBuilder,
|