meocord 3.2.0 → 3.2.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/CHANGELOG.md +9 -0
- package/LICENSE +1 -1
- package/README.md +7 -24
- package/dist/cjs/_shared/{controller.decorator-MUHA_A3z.cjs → controller.decorator-eT0oHb8D.cjs} +1 -1
- package/dist/cjs/_shared/{metadata-key.enum-BzzvGUId.cjs → metadata-key.enum-DITxfZlw.cjs} +1 -1
- package/dist/cjs/_shared/{theme-Bz-D4RbT.cjs → theme-EmG1ZEwV.cjs} +4 -4
- package/dist/cjs/common/index.cjs +2 -2
- package/dist/cjs/core/index.cjs +44 -21
- package/dist/cjs/decorator/index.cjs +2 -2
- package/dist/cjs/enum/index.cjs +1 -1
- package/dist/cjs/testing/index.cjs +2 -2
- package/dist/esm/bin/meocord.js +6 -2
- package/dist/esm/common/decorator.js +1 -1
- package/dist/esm/common/theme.js +1 -1
- package/dist/esm/core/meocord.app.js +42 -19
- package/dist/esm/enum/controller.enum.js +1 -1
- package/dist/esm/enum/metadata-key.enum.js +1 -1
- package/dist/esm/package.json.js +1 -1
- package/dist/esm/testing/mock-fn.js +1 -1
- package/dist/esm/util/json.util.js +1 -1
- package/dist/esm/util/meocord-cli.util.js +1 -1
- package/dist/esm/util/runtime.util.js +1 -1
- package/dist/esm/util/wait.util.js +1 -1
- package/dist/types/common/index.d.ts +3 -3
- package/dist/types/core/index.d.ts +2 -2
- package/dist/types/decorator/index.d.ts +5 -5
- package/dist/types/enum/index.d.ts +1 -1
- package/dist/types/interface/index.d.ts +2 -2
- package/dist/types/testing/index.d.ts +3 -3
- package/meocord.eslint.cjs +1 -1
- package/meocord.eslint.d.ts +1 -1
- package/meocord.eslint.mjs +1 -1
- package/package.json +19 -17
- package/webpack.config.js +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# meocord
|
|
2
|
+
|
|
3
|
+
## 3.2.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#13](https://github.com/l7aromeo/meocord/pull/13) [`f8a6b15`](https://github.com/l7aromeo/meocord/commit/f8a6b156e8d22abf88443ba77c605d6d47991ab4) Thanks [@l7aromeo](https://github.com/l7aromeo)! - Update the shipped dependencies — `@clack/prompts` 1.8.0, `@swc/core` 1.16.2, and `webpack`
|
|
8
|
+
5.110.3 — and state the copyright as `2025-present`, including in the notice the CLI prints
|
|
9
|
+
under `--license` and in its help banner.
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
3
|
+
Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# MeoCord Framework
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/meocord)
|
|
4
|
+
[](https://github.com/l7aromeo/meocord/actions/workflows/release.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/meocord)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
3
8
|
**MeoCord** is a decorator-based Discord bot framework built on top of discord.js. It brings a NestJS-style architecture — controllers, services, guards, and dependency injection — to bot development, with a full CLI, TypeScript-first design, and testing utilities included out of the box.
|
|
4
9
|
|
|
5
10
|
---
|
|
@@ -1003,31 +1008,9 @@ MEOCORD_RUNTIME=/usr/local/bin/bun npm run start
|
|
|
1003
1008
|
|
|
1004
1009
|
## Contributing
|
|
1005
1010
|
|
|
1006
|
-
|
|
1007
|
-
2. Create a feature branch: `git checkout -b feat/your-feature`
|
|
1008
|
-
3. Commit with conventional commits: `git commit -m "feat: add X"`
|
|
1009
|
-
4. Run `bun run lint` and `bun run test` before pushing
|
|
1010
|
-
5. If you touched anything under `src/bin/`, also run `bun run build && bun run verify:generated`
|
|
1011
|
-
6. Push and open a pull request against `main`
|
|
1012
|
-
|
|
1013
|
-
Include a description of what changed and why, and add tests for any new behaviour.
|
|
1014
|
-
|
|
1015
|
-
`verify:generated` generates one controller of every type through the built CLI — flat and nested, in separate throwaway projects — and typechecks the result against the published package. Rendering a template says nothing about whether the code it produces compiles, and two bugs lived behind exactly that gap. It runs in CI as part of the Build job, so you do not have to remember it; running it locally is just faster than waiting.
|
|
1016
|
-
|
|
1017
|
-
### Commit messages and releases
|
|
1018
|
-
|
|
1019
|
-
Commit messages drive versioning through [semantic-release](https://semantic-release.gitbook.io/). Only these publish:
|
|
1020
|
-
|
|
1021
|
-
| Prefix | Release |
|
|
1022
|
-
| ------------------------------ | ------- |
|
|
1023
|
-
| `feat:` | minor |
|
|
1024
|
-
| `fix:` | patch |
|
|
1025
|
-
| `perf:` | patch |
|
|
1026
|
-
| `BREAKING CHANGE:` in the body | major |
|
|
1027
|
-
|
|
1028
|
-
Everything else — `docs:`, `test:`, `ci:`, `chore:`, `refactor:`, `style:` — lands on `main` without publishing and ships with whatever releasable commit comes next.
|
|
1011
|
+
Issues, questions, and pull requests are welcome. [CONTRIBUTING.md](./CONTRIBUTING.md) covers getting set up, what each check exists to catch, and how releases work — a change that reaches the published package carries a [changeset](https://github.com/changesets/changesets), and merging the release pull request is what publishes it.
|
|
1029
1012
|
|
|
1030
|
-
|
|
1013
|
+
Participation is governed by the [Code of Conduct](./CODE_OF_CONDUCT.md). For vulnerabilities, follow [SECURITY.md](./SECURITY.md) rather than opening an issue.
|
|
1031
1014
|
|
|
1032
1015
|
---
|
|
1033
1016
|
|
package/dist/cjs/_shared/{controller.decorator-MUHA_A3z.cjs → controller.decorator-eT0oHb8D.cjs}
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require('reflect-metadata');
|
|
4
4
|
var inversify = require('inversify');
|
|
5
5
|
var enum_index = require('../enum/index.cjs');
|
|
6
|
-
var metadataKey_enum = require('./metadata-key.enum-
|
|
6
|
+
var metadataKey_enum = require('./metadata-key.enum-DITxfZlw.cjs');
|
|
7
7
|
var discord_js = require('discord.js');
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -12,7 +12,7 @@ var chalk = require('chalk');
|
|
|
12
12
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
13
13
|
/**
|
|
14
14
|
* MeoCord Framework
|
|
15
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
15
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
16
16
|
* SPDX-License-Identifier: MIT
|
|
17
17
|
*/ /**
|
|
18
18
|
* Helper function to fix common JSON formatting issues in tsconfig.json, such as:
|
|
@@ -55,7 +55,7 @@ let configLoaded = false;
|
|
|
55
55
|
const compiledPath = path.resolve(process.cwd(), 'dist', 'meocord.config.mjs');
|
|
56
56
|
if (!fs.existsSync(compiledPath)) return undefined;
|
|
57
57
|
try {
|
|
58
|
-
const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('_shared/theme-
|
|
58
|
+
const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('_shared/theme-EmG1ZEwV.cjs', document.baseURI).href)), {
|
|
59
59
|
interopDefault: true
|
|
60
60
|
});
|
|
61
61
|
return jiti$1(compiledPath);
|
|
@@ -83,7 +83,7 @@ let configLoaded = false;
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('_shared/theme-
|
|
86
|
+
const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('_shared/theme-EmG1ZEwV.cjs', document.baseURI).href)), {
|
|
87
87
|
interopDefault: true,
|
|
88
88
|
alias: aliases,
|
|
89
89
|
moduleCache: false
|
|
@@ -165,7 +165,7 @@ class Logger {
|
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
167
|
* MeoCord Framework
|
|
168
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
168
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
169
169
|
* SPDX-License-Identifier: MIT
|
|
170
170
|
*/ class Theme {
|
|
171
171
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var theme = require('../_shared/theme-
|
|
3
|
+
var theme = require('../_shared/theme-EmG1ZEwV.cjs');
|
|
4
4
|
require('node:util');
|
|
5
5
|
require('dayjs');
|
|
6
6
|
require('dayjs/plugin/utc.js');
|
|
@@ -12,7 +12,7 @@ require('chalk');
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* MeoCord Framework
|
|
15
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
15
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
16
16
|
* SPDX-License-Identifier: MIT
|
|
17
17
|
*/ /**
|
|
18
18
|
* Composes multiple class or method decorators into a single decorator.
|
package/dist/cjs/core/index.cjs
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
require('reflect-metadata');
|
|
4
4
|
var inversify = require('inversify');
|
|
5
5
|
var discord_js = require('discord.js');
|
|
6
|
-
var theme = require('../_shared/theme-
|
|
7
|
-
var controller_decorator = require('../_shared/controller.decorator-
|
|
6
|
+
var theme = require('../_shared/theme-EmG1ZEwV.cjs');
|
|
7
|
+
var controller_decorator = require('../_shared/controller.decorator-eT0oHb8D.cjs');
|
|
8
8
|
var lodashEs = require('lodash-es');
|
|
9
9
|
var enum_index = require('../enum/index.cjs');
|
|
10
10
|
var Table = require('cli-table3');
|
|
11
|
-
var metadataKey_enum = require('../_shared/metadata-key.enum-
|
|
11
|
+
var metadataKey_enum = require('../_shared/metadata-key.enum-DITxfZlw.cjs');
|
|
12
12
|
require('node:util');
|
|
13
13
|
require('dayjs');
|
|
14
14
|
require('dayjs/plugin/utc.js');
|
|
@@ -26,23 +26,44 @@ const createErrorEmbed = (description)=>{
|
|
|
26
26
|
return embed;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
/** What Discord assumes a command body is when it carries no type of its own. */ const DEFAULT_APPLICATION_COMMAND_TYPE = discord_js.ApplicationCommandType.ChatInput;
|
|
29
30
|
/**
|
|
30
|
-
* The
|
|
31
|
+
* The body a builder registers, which is what Discord sees.
|
|
31
32
|
*
|
|
32
|
-
* Read from the built payload rather than from the `@Command`
|
|
33
|
-
* free to
|
|
34
|
-
|
|
35
|
-
*/ function commandNameOf(builder) {
|
|
33
|
+
* Read from the built payload rather than from the `@Command` arguments: a builder is
|
|
34
|
+
* free to describe the command differently from the strings it was handed.
|
|
35
|
+
*/ function payloadOf(builder) {
|
|
36
36
|
try {
|
|
37
|
-
|
|
38
|
-
return typeof json?.name === 'string' ? json.name : undefined;
|
|
37
|
+
return typeof builder.toJSON === 'function' ? builder.toJSON() : builder;
|
|
39
38
|
} catch {
|
|
40
39
|
// A builder missing a required field throws from toJSON. Surfacing that is the
|
|
41
40
|
// registration call's job, where it is reported against the command Discord
|
|
42
41
|
// rejected -- deduplication should not be what turns it into a startup crash.
|
|
43
|
-
return
|
|
42
|
+
return {};
|
|
44
43
|
}
|
|
45
44
|
}
|
|
45
|
+
/** The name a builder registers under. */ function commandNameOf(builder) {
|
|
46
|
+
const { name } = payloadOf(builder);
|
|
47
|
+
return typeof name === 'string' ? name : undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The application command type a builder registers as.
|
|
51
|
+
*
|
|
52
|
+
* A slash builder may leave the field out, so an absent type is read as the chat input
|
|
53
|
+
* one Discord would infer — which keeps untyped slash builders colliding with each
|
|
54
|
+
* other rather than each claiming a key of its own.
|
|
55
|
+
*/ function commandTypeOf(builder) {
|
|
56
|
+
const { type } = payloadOf(builder);
|
|
57
|
+
return typeof type === 'number' ? type : DEFAULT_APPLICATION_COMMAND_TYPE;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The identity Discord gives a command.
|
|
61
|
+
*
|
|
62
|
+
* The numeric type leads, so the two halves can never be read apart wrongly: everything
|
|
63
|
+
* before the first separator is the type, everything after it is the name.
|
|
64
|
+
*/ function registrationKey(builder, fallbackName) {
|
|
65
|
+
return `${commandTypeOf(builder)}:${commandNameOf(builder) ?? fallbackName}`;
|
|
66
|
+
}
|
|
46
67
|
class MeoCordApp {
|
|
47
68
|
/**
|
|
48
69
|
* Runs an event handler so a failure inside it cannot take the process down.
|
|
@@ -109,11 +130,13 @@ class MeoCordApp {
|
|
|
109
130
|
}
|
|
110
131
|
}
|
|
111
132
|
async registerCommands() {
|
|
112
|
-
// Keyed by
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
|
|
133
|
+
// Keyed by type and name together, because that pair is what Discord treats as one
|
|
134
|
+
// command: a user context menu and a message context menu are free to share a name,
|
|
135
|
+
// and keying on the name alone would drop one of them from the payload. Within a
|
|
136
|
+
// single type the name is unique, so a command whose subcommands live in separate
|
|
137
|
+
// methods still contributes its builder once — sending it twice makes Discord
|
|
138
|
+
// reject the whole payload.
|
|
139
|
+
const buildersByCommand = new Map();
|
|
117
140
|
for (const controllerClass of this.controllerClasses){
|
|
118
141
|
const instance = this.getInstance(controllerClass);
|
|
119
142
|
const commandMap = controller_decorator.getCommandMap(instance);
|
|
@@ -122,18 +145,18 @@ class MeoCordApp {
|
|
|
122
145
|
if (!Array.isArray(commandMetadataArray)) continue;
|
|
123
146
|
for (const { builder, type } of commandMetadataArray){
|
|
124
147
|
if (!(type in enum_index.CommandType) || !builder) continue;
|
|
125
|
-
const
|
|
126
|
-
const existing =
|
|
148
|
+
const key = registrationKey(builder, commandName);
|
|
149
|
+
const existing = buildersByCommand.get(key);
|
|
127
150
|
if (existing === undefined) {
|
|
128
|
-
|
|
151
|
+
buildersByCommand.set(key, builder);
|
|
129
152
|
} else if (existing !== builder) {
|
|
130
|
-
this.logger.warn(`Command "${
|
|
153
|
+
this.logger.warn(`Command "${commandNameOf(builder) ?? commandName}" is built more than once for the same ` + `application command type; only the first builder is registered. Two builders of one type ` + `cannot both own a name, so declare the builder on a single @Command and give the others ` + `the plain CommandType.`);
|
|
131
154
|
}
|
|
132
155
|
}
|
|
133
156
|
}
|
|
134
157
|
}
|
|
135
158
|
const builders = [
|
|
136
|
-
...
|
|
159
|
+
...buildersByCommand.values()
|
|
137
160
|
];
|
|
138
161
|
try {
|
|
139
162
|
if (this.bot.application) {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require('reflect-metadata');
|
|
4
4
|
var inversify = require('inversify');
|
|
5
|
-
var metadataKey_enum = require('../_shared/metadata-key.enum-
|
|
6
|
-
var controller_decorator = require('../_shared/controller.decorator-
|
|
5
|
+
var metadataKey_enum = require('../_shared/metadata-key.enum-DITxfZlw.cjs');
|
|
6
|
+
var controller_decorator = require('../_shared/controller.decorator-eT0oHb8D.cjs');
|
|
7
7
|
var discord_js = require('discord.js');
|
|
8
8
|
require('../enum/index.cjs');
|
|
9
9
|
|
package/dist/cjs/enum/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require('reflect-metadata');
|
|
4
4
|
var inversify = require('inversify');
|
|
5
|
-
var metadataKey_enum = require('../_shared/metadata-key.enum-
|
|
5
|
+
var metadataKey_enum = require('../_shared/metadata-key.enum-DITxfZlw.cjs');
|
|
6
6
|
var discord_js = require('discord.js');
|
|
7
7
|
|
|
8
8
|
function isValueProvider(p) {
|
|
@@ -122,7 +122,7 @@ function isValueProvider(p) {
|
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* MeoCord Framework
|
|
125
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
125
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
126
126
|
* SPDX-License-Identifier: MIT
|
|
127
127
|
*/ // ---------------------------------------------------------------------------
|
|
128
128
|
// Framework-agnostic mock function
|
package/dist/esm/bin/meocord.js
CHANGED
|
@@ -82,7 +82,7 @@ SOFTWARE.
|
|
|
82
82
|
console.log(`
|
|
83
83
|
MIT License
|
|
84
84
|
|
|
85
|
-
Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
85
|
+
Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
86
86
|
|
|
87
87
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
88
88
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -164,7 +164,11 @@ copies or substantial portions of the Software.
|
|
|
164
164
|
})),
|
|
165
165
|
initialValue: defaultPM
|
|
166
166
|
});
|
|
167
|
-
|
|
167
|
+
// `select` types its cancel sentinel as plain `symbol`, while `isCancel` narrows only
|
|
168
|
+
// that sentinel's own `unique symbol` — so the guard leaves `symbol` in its false
|
|
169
|
+
// branch and `pm` stops being a PackageManager. The prompt returns a symbol in no
|
|
170
|
+
// other case, so the cancel is detected on that instead.
|
|
171
|
+
if (typeof selected === 'symbol') {
|
|
168
172
|
p.cancel('Operation cancelled.');
|
|
169
173
|
process.exit(0);
|
|
170
174
|
}
|
package/dist/esm/common/theme.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SlashCommandBuilder, MessageFlagsBitField } from 'discord.js';
|
|
1
|
+
import { ApplicationCommandType, SlashCommandBuilder, MessageFlagsBitField } from 'discord.js';
|
|
2
2
|
import { Logger } from '../common/logger.js';
|
|
3
3
|
import '../common/theme.js';
|
|
4
4
|
import { getCommandMap, findAmbiguousRoutes, PARAM_SEPARATOR, getAutocompleteHandlers, getMessageHandlers, getReactionHandlers } from '../decorator/controller.decorator.js';
|
|
@@ -8,23 +8,44 @@ import { describeInteraction, hasCustomId, matchesCommandType, resolveCommandPat
|
|
|
8
8
|
import { ReactionHandlerAction, CommandType } from '../enum/controller.enum.js';
|
|
9
9
|
import CliTable3 from 'cli-table3';
|
|
10
10
|
|
|
11
|
+
/** What Discord assumes a command body is when it carries no type of its own. */ const DEFAULT_APPLICATION_COMMAND_TYPE = ApplicationCommandType.ChatInput;
|
|
11
12
|
/**
|
|
12
|
-
* The
|
|
13
|
+
* The body a builder registers, which is what Discord sees.
|
|
13
14
|
*
|
|
14
|
-
* Read from the built payload rather than from the `@Command`
|
|
15
|
-
* free to
|
|
16
|
-
|
|
17
|
-
*/ function commandNameOf(builder) {
|
|
15
|
+
* Read from the built payload rather than from the `@Command` arguments: a builder is
|
|
16
|
+
* free to describe the command differently from the strings it was handed.
|
|
17
|
+
*/ function payloadOf(builder) {
|
|
18
18
|
try {
|
|
19
|
-
|
|
20
|
-
return typeof json?.name === 'string' ? json.name : undefined;
|
|
19
|
+
return typeof builder.toJSON === 'function' ? builder.toJSON() : builder;
|
|
21
20
|
} catch {
|
|
22
21
|
// A builder missing a required field throws from toJSON. Surfacing that is the
|
|
23
22
|
// registration call's job, where it is reported against the command Discord
|
|
24
23
|
// rejected -- deduplication should not be what turns it into a startup crash.
|
|
25
|
-
return
|
|
24
|
+
return {};
|
|
26
25
|
}
|
|
27
26
|
}
|
|
27
|
+
/** The name a builder registers under. */ function commandNameOf(builder) {
|
|
28
|
+
const { name } = payloadOf(builder);
|
|
29
|
+
return typeof name === 'string' ? name : undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The application command type a builder registers as.
|
|
33
|
+
*
|
|
34
|
+
* A slash builder may leave the field out, so an absent type is read as the chat input
|
|
35
|
+
* one Discord would infer — which keeps untyped slash builders colliding with each
|
|
36
|
+
* other rather than each claiming a key of its own.
|
|
37
|
+
*/ function commandTypeOf(builder) {
|
|
38
|
+
const { type } = payloadOf(builder);
|
|
39
|
+
return typeof type === 'number' ? type : DEFAULT_APPLICATION_COMMAND_TYPE;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The identity Discord gives a command.
|
|
43
|
+
*
|
|
44
|
+
* The numeric type leads, so the two halves can never be read apart wrongly: everything
|
|
45
|
+
* before the first separator is the type, everything after it is the name.
|
|
46
|
+
*/ function registrationKey(builder, fallbackName) {
|
|
47
|
+
return `${commandTypeOf(builder)}:${commandNameOf(builder) ?? fallbackName}`;
|
|
48
|
+
}
|
|
28
49
|
class MeoCordApp {
|
|
29
50
|
/**
|
|
30
51
|
* Runs an event handler so a failure inside it cannot take the process down.
|
|
@@ -91,11 +112,13 @@ class MeoCordApp {
|
|
|
91
112
|
}
|
|
92
113
|
}
|
|
93
114
|
async registerCommands() {
|
|
94
|
-
// Keyed by
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
115
|
+
// Keyed by type and name together, because that pair is what Discord treats as one
|
|
116
|
+
// command: a user context menu and a message context menu are free to share a name,
|
|
117
|
+
// and keying on the name alone would drop one of them from the payload. Within a
|
|
118
|
+
// single type the name is unique, so a command whose subcommands live in separate
|
|
119
|
+
// methods still contributes its builder once — sending it twice makes Discord
|
|
120
|
+
// reject the whole payload.
|
|
121
|
+
const buildersByCommand = new Map();
|
|
99
122
|
for (const controllerClass of this.controllerClasses){
|
|
100
123
|
const instance = this.getInstance(controllerClass);
|
|
101
124
|
const commandMap = getCommandMap(instance);
|
|
@@ -104,18 +127,18 @@ class MeoCordApp {
|
|
|
104
127
|
if (!Array.isArray(commandMetadataArray)) continue;
|
|
105
128
|
for (const { builder, type } of commandMetadataArray){
|
|
106
129
|
if (!(type in CommandType) || !builder) continue;
|
|
107
|
-
const
|
|
108
|
-
const existing =
|
|
130
|
+
const key = registrationKey(builder, commandName);
|
|
131
|
+
const existing = buildersByCommand.get(key);
|
|
109
132
|
if (existing === undefined) {
|
|
110
|
-
|
|
133
|
+
buildersByCommand.set(key, builder);
|
|
111
134
|
} else if (existing !== builder) {
|
|
112
|
-
this.logger.warn(`Command "${
|
|
135
|
+
this.logger.warn(`Command "${commandNameOf(builder) ?? commandName}" is built more than once for the same ` + `application command type; only the first builder is registered. Two builders of one type ` + `cannot both own a name, so declare the builder on a single @Command and give the others ` + `the plain CommandType.`);
|
|
113
136
|
}
|
|
114
137
|
}
|
|
115
138
|
}
|
|
116
139
|
}
|
|
117
140
|
const builders = [
|
|
118
|
-
...
|
|
141
|
+
...buildersByCommand.values()
|
|
119
142
|
];
|
|
120
143
|
try {
|
|
121
144
|
if (this.bot.application) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MeoCord Framework
|
|
3
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
3
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/ var ControllerType = /*#__PURE__*/ function(ControllerType) {
|
|
6
6
|
ControllerType["BUTTON"] = "button";
|
package/dist/esm/package.json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MeoCord Framework
|
|
3
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
3
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/ // ---------------------------------------------------------------------------
|
|
6
6
|
// Framework-agnostic mock function
|
|
@@ -23,7 +23,7 @@ function configureCommandHelp(command) {
|
|
|
23
23
|
* @param options - The options available for the command.
|
|
24
24
|
* @returns The formatted help text.
|
|
25
25
|
*/ function formatHelp(cmd, helper, options) {
|
|
26
|
-
let helpText = `MeoCord Copyright (c) 2025 Ukasyah Rahmatullah Zada — MIT License\n\n`;
|
|
26
|
+
let helpText = `MeoCord Copyright (c) 2025-present Ukasyah Rahmatullah Zada — MIT License\n\n`;
|
|
27
27
|
helpText += `${helper.commandUsage(cmd)}\n\n`;
|
|
28
28
|
helpText += `${helper.commandDescription(cmd)}\n\n`;
|
|
29
29
|
if (cmd.registeredArguments.length > 0) {
|
|
@@ -2,7 +2,7 @@ import { ColorResolvable } from 'discord.js';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* MeoCord Framework
|
|
5
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
5
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
6
6
|
* SPDX-License-Identifier: MIT
|
|
7
7
|
*/
|
|
8
8
|
declare class Logger {
|
|
@@ -21,7 +21,7 @@ declare class Logger {
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* MeoCord Framework
|
|
24
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
24
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
25
25
|
* SPDX-License-Identifier: MIT
|
|
26
26
|
*/
|
|
27
27
|
|
|
@@ -34,7 +34,7 @@ declare class Theme {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* MeoCord Framework
|
|
37
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
37
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
38
38
|
* SPDX-License-Identifier: MIT
|
|
39
39
|
*/
|
|
40
40
|
/**
|
|
@@ -3,7 +3,7 @@ import { Client, ActivityOptions } from 'discord.js';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* MeoCord Framework
|
|
6
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
6
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -124,7 +124,7 @@ declare class MeoCordApp {
|
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
126
|
* MeoCord Framework
|
|
127
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
127
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
128
128
|
* SPDX-License-Identifier: MIT
|
|
129
129
|
*/
|
|
130
130
|
|
|
@@ -6,7 +6,7 @@ import 'webpack';
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* MeoCord Framework
|
|
9
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
9
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
10
10
|
* SPDX-License-Identifier: MIT
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -31,7 +31,7 @@ declare function Service<T>(): (target: new (...args: any[]) => T) => void;
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* MeoCord Framework
|
|
34
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
34
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
35
35
|
* SPDX-License-Identifier: MIT
|
|
36
36
|
*/
|
|
37
37
|
|
|
@@ -57,7 +57,7 @@ declare function CommandBuilder<T extends BuildableCommandType>(commandType: T):
|
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* MeoCord Framework
|
|
60
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
60
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
61
61
|
* SPDX-License-Identifier: MIT
|
|
62
62
|
*/
|
|
63
63
|
|
|
@@ -231,7 +231,7 @@ declare function findAmbiguousRoutes(patterns: string[]): [string, string][];
|
|
|
231
231
|
|
|
232
232
|
/**
|
|
233
233
|
* MeoCord Framework
|
|
234
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
234
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
235
235
|
* SPDX-License-Identifier: MIT
|
|
236
236
|
*/
|
|
237
237
|
|
|
@@ -319,7 +319,7 @@ declare function UseGuard(...guards: ((new (...args: any[]) => GuardInterface) |
|
|
|
319
319
|
|
|
320
320
|
/**
|
|
321
321
|
* MeoCord Framework
|
|
322
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
322
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
323
323
|
* SPDX-License-Identifier: MIT
|
|
324
324
|
*/
|
|
325
325
|
|
|
@@ -4,7 +4,7 @@ import { CommandType, ReactionHandlerAction } from '../enum/index.js';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* MeoCord Framework
|
|
7
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
7
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
8
8
|
* SPDX-License-Identifier: MIT
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -90,7 +90,7 @@ type CommandInteractionType<CBC extends BuildableCommandType, T extends CommandB
|
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* MeoCord Framework
|
|
93
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
93
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
94
94
|
* SPDX-License-Identifier: MIT
|
|
95
95
|
*/
|
|
96
96
|
|
|
@@ -6,7 +6,7 @@ import '../controller.enum-DYfhYaat.js';
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* MeoCord Framework
|
|
9
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
9
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
10
10
|
* SPDX-License-Identifier: MIT
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -78,7 +78,7 @@ declare class MeoCordTestingModule {
|
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* MeoCord Framework
|
|
81
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
81
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
82
82
|
* SPDX-License-Identifier: MIT
|
|
83
83
|
*/
|
|
84
84
|
interface MockResult<T = unknown> {
|
|
@@ -142,7 +142,7 @@ declare function createMockFn<T extends (...args: any[]) => any = (...args: any[
|
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
144
|
* MeoCord Framework
|
|
145
|
-
* Copyright (c) 2025 Ukasyah Rahmatullah Zada
|
|
145
|
+
* Copyright (c) 2025-present Ukasyah Rahmatullah Zada
|
|
146
146
|
* SPDX-License-Identifier: MIT
|
|
147
147
|
*/
|
|
148
148
|
|
package/meocord.eslint.cjs
CHANGED
package/meocord.eslint.d.ts
CHANGED
package/meocord.eslint.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meocord",
|
|
3
3
|
"description": "Decorator-based Discord bot framework built on discord.js. Brings NestJS-style controllers, dependency injection, guards, and testing utilities to bot development — with a full CLI and TypeScript-first design.",
|
|
4
|
-
"version": "3.2.
|
|
4
|
+
"version": "3.2.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=22"
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
"verify:generated": "bun scripts/verify-generated.ts",
|
|
17
17
|
"test:watch": "vitest",
|
|
18
18
|
"test:coverage": "vitest run --coverage",
|
|
19
|
-
"test:typecheck": "tsc --noEmit --project tsconfig.test.json"
|
|
19
|
+
"test:typecheck": "tsc --noEmit --project tsconfig.test.json",
|
|
20
|
+
"changeset": "changeset",
|
|
21
|
+
"release:version": "changeset version",
|
|
22
|
+
"release:publish": "changeset publish"
|
|
20
23
|
},
|
|
21
24
|
"bin": "./dist/esm/bin/meocord.js",
|
|
22
25
|
"repository": {
|
|
@@ -74,11 +77,12 @@
|
|
|
74
77
|
"package.json",
|
|
75
78
|
"LICENSE",
|
|
76
79
|
"AUTHOR.md",
|
|
80
|
+
"CHANGELOG.md",
|
|
77
81
|
"README.md"
|
|
78
82
|
],
|
|
79
83
|
"dependencies": {
|
|
80
|
-
"@clack/prompts": "^1.
|
|
81
|
-
"@swc/core": "1.16.
|
|
84
|
+
"@clack/prompts": "^1.8.0",
|
|
85
|
+
"@swc/core": "1.16.2",
|
|
82
86
|
"chalk": "^6.0.0",
|
|
83
87
|
"cli-table3": "^0.6.5",
|
|
84
88
|
"commander": "^15.0.0",
|
|
@@ -91,40 +95,38 @@
|
|
|
91
95
|
"swc-loader": "^0.2.7",
|
|
92
96
|
"terser-webpack-plugin": "^5.6.1",
|
|
93
97
|
"tsconfig-paths-webpack-plugin": "^4.2.0",
|
|
94
|
-
"webpack": "^5.
|
|
98
|
+
"webpack": "^5.110.3",
|
|
95
99
|
"webpack-node-externals": "^3.0.0"
|
|
96
100
|
},
|
|
97
101
|
"devDependencies": {
|
|
102
|
+
"@changesets/changelog-github": "^1.0.1",
|
|
103
|
+
"@changesets/cli": "^3.0.2",
|
|
98
104
|
"@eslint/js": "^10.0.1",
|
|
99
105
|
"@rollup/plugin-alias": "^6.0.0",
|
|
100
106
|
"@rollup/plugin-json": "^6.1.0",
|
|
101
107
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
102
108
|
"@rollup/plugin-swc": "^0.4.1",
|
|
103
|
-
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
104
|
-
"@semantic-release/github": "^12.0.9",
|
|
105
|
-
"@semantic-release/release-notes-generator": "^14.1.1",
|
|
106
109
|
"@types/lodash-es": "^4.17.12",
|
|
107
110
|
"@types/webpack-node-externals": "^3.0.4",
|
|
108
|
-
"@typescript-eslint/parser": "^8.
|
|
111
|
+
"@typescript-eslint/parser": "^8.70.0",
|
|
109
112
|
"discord.js": "^14.27.0",
|
|
110
|
-
"eslint": "^10.
|
|
113
|
+
"eslint": "^10.10.0",
|
|
111
114
|
"eslint-config-prettier": "^10.1.8",
|
|
112
115
|
"eslint-plugin-headers": "^1.3.4",
|
|
113
116
|
"eslint-plugin-import-x": "^4.17.1",
|
|
114
117
|
"eslint-plugin-prettier": "^5.5.6",
|
|
115
118
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
116
|
-
"globals": "^17.
|
|
119
|
+
"globals": "^17.12.0",
|
|
117
120
|
"husky": "^9.1.7",
|
|
118
121
|
"prettier": "^3.9.6",
|
|
119
|
-
"rollup": "^4.
|
|
122
|
+
"rollup": "^4.63.1",
|
|
120
123
|
"rollup-plugin-copy": "^3.5.0",
|
|
121
124
|
"rollup-plugin-dts": "^6.5.1",
|
|
122
|
-
"semantic-release": "^25.0.9",
|
|
123
125
|
"typescript": "^6.0.3",
|
|
124
|
-
"typescript-eslint": "^8.
|
|
125
|
-
"@vitest/coverage-istanbul": "^
|
|
126
|
-
"unplugin-swc": "^1.
|
|
127
|
-
"vitest": "^
|
|
126
|
+
"typescript-eslint": "^8.70.0",
|
|
127
|
+
"@vitest/coverage-istanbul": "^5.0.0",
|
|
128
|
+
"unplugin-swc": "^1.6.0",
|
|
129
|
+
"vitest": "^5.0.0"
|
|
128
130
|
},
|
|
129
131
|
"peerDependencies": {
|
|
130
132
|
"discord.js": "^14.26.4",
|