meocord 4.0.0-beta.1 → 4.0.0-beta.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 +25 -0
- package/dist/cjs/core/index.cjs +24 -22
- package/dist/esm/bin/app-template/src/main.ts.template +5 -1
- package/dist/esm/bin/app-template/tsconfig.json.template +2 -2
- package/dist/esm/bin/builder-template/controller/message.controller.template +2 -2
- package/dist/esm/bin/builder-template/controller/reaction.controller.template +5 -5
- package/dist/esm/bin/builder-template/guard.template +2 -2
- package/dist/esm/core/meocord.app.js +24 -22
- package/dist/esm/package.json.js +1 -1
- package/dist/types/common/index.d.cts +53 -0
- package/dist/types/controller.enum-DYfhYaat.d.cts +36 -0
- package/dist/types/core/index.d.cts +131 -0
- package/dist/types/core/index.d.ts +7 -0
- package/dist/types/decorator/index.d.cts +340 -0
- package/dist/types/enum/index.d.cts +40 -0
- package/dist/types/interface/index.d.cts +170 -0
- package/dist/types/testing/index.d.cts +274 -0
- package/meocord.eslint.d.cts +13 -0
- package/package.json +58 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# meocord
|
|
2
2
|
|
|
3
|
+
## 4.0.0-beta.2
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#36](https://github.com/l7aromeo/meocord/pull/36) [`45e564e`](https://github.com/l7aromeo/meocord/commit/45e564e6baff17313037372ec56baa1711a3584c) Thanks [@l7aromeo](https://github.com/l7aromeo)! - **Breaking:** `app.start()` rejects when the login fails. It logged the error and resolved, so a bot
|
|
8
|
+
with an invalid token went on to log "Application started" and exit with code 0, which Docker's
|
|
9
|
+
`restart: on-failure`, systemd and CI all read as success. New applications' `main.ts` sets
|
|
10
|
+
`process.exitCode = 1` when startup fails; add the same to an existing entry point's `catch`. See the
|
|
11
|
+
[migration guide](https://github.com/l7aromeo/meocord/blob/main/docs/MIGRATING.md#4-build-and-start).
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#37](https://github.com/l7aromeo/meocord/pull/37) Thanks [@l7aromeo](https://github.com/l7aromeo)! - Type the CommonJS build as CommonJS. Every entry point's `require` condition resolved to the ESM
|
|
16
|
+
declarations, so a CommonJS TypeScript project was told `meocord/core` is an ES module it cannot
|
|
17
|
+
`require`, even with `skipLibCheck`. Each entry now ships `.d.cts` declarations for `require`, and
|
|
18
|
+
`meocord/eslint` types its `module.exports` array as what `require` returns.
|
|
19
|
+
|
|
20
|
+
- [#35](https://github.com/l7aromeo/meocord/pull/35) [`b93a771`](https://github.com/l7aromeo/meocord/commit/b93a771b19664345fec4222d5a2c29dcf5b31a0d) Thanks [@l7aromeo](https://github.com/l7aromeo)! - Generate code that passes a new application's own `lint`. A generated guard failed `tsc` and ESLint
|
|
21
|
+
— `GuardInterface` imported as a value, and an unused `context` parameter — and generated message and
|
|
22
|
+
reaction controllers imported names they never used, which only the application's ESLint, run in the
|
|
23
|
+
background after generating, removed. New applications also typecheck `meocord.config.ts`: the
|
|
24
|
+
template's `tsconfig.json` includes it instead of excluding it, so a type error in the config fails
|
|
25
|
+
`lint`, and editors resolve `paths` aliases imported there. `noEmit` stays on, so `tsc` writes nothing
|
|
26
|
+
beside it.
|
|
27
|
+
|
|
3
28
|
## 4.0.0-beta.1
|
|
4
29
|
|
|
5
30
|
### Major Changes
|
package/dist/cjs/core/index.cjs
CHANGED
|
@@ -106,28 +106,30 @@ class MeoCordApp {
|
|
|
106
106
|
}
|
|
107
107
|
return this.controllerInstancesCache.get(controllerClass);
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Registers the Discord event handlers and logs in.
|
|
111
|
+
*
|
|
112
|
+
* Rejects when the login fails -- an invalid token, or Discord unreachable -- so the caller can
|
|
113
|
+
* stop with a non-zero exit code. A bot that never came online is a failed start, and a
|
|
114
|
+
* supervisor such as Docker's `restart: on-failure` or systemd can only tell if the process says so.
|
|
115
|
+
*/ async start() {
|
|
116
|
+
this.logger.log('Starting bot...');
|
|
117
|
+
this.bot.on('clientReady', ()=>this.runListener('clientReady', async ()=>{
|
|
118
|
+
this.activityInterval = setInterval(()=>this.updateActivity(), 10000);
|
|
119
|
+
await this.registerCommands();
|
|
120
|
+
}));
|
|
121
|
+
this.bot.on('interactionCreate', (interaction)=>this.runListener('interactionCreate', ()=>this.handleInteraction(interaction)));
|
|
122
|
+
this.bot.on('messageCreate', (message)=>this.runListener('messageCreate', ()=>this.handleMessage(message)));
|
|
123
|
+
this.bot.on('messageReactionAdd', (reaction, user)=>this.runListener('messageReactionAdd', ()=>this.handleReaction(reaction, {
|
|
124
|
+
user,
|
|
125
|
+
action: enum_index.ReactionHandlerAction.ADD
|
|
126
|
+
})));
|
|
127
|
+
this.bot.on('messageReactionRemove', (reaction, user)=>this.runListener('messageReactionRemove', ()=>this.handleReaction(reaction, {
|
|
128
|
+
user,
|
|
129
|
+
action: enum_index.ReactionHandlerAction.REMOVE
|
|
130
|
+
})));
|
|
131
|
+
await this.bot.login(this.discordToken);
|
|
132
|
+
this.logger.log('Bot is online!');
|
|
131
133
|
}
|
|
132
134
|
async registerCommands() {
|
|
133
135
|
// Keyed by type and name together, because that pair is what Discord treats as one
|
|
@@ -11,4 +11,8 @@ async function bootstrap() {
|
|
|
11
11
|
logger.log('Application started')
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
bootstrap().catch(error =>
|
|
14
|
+
bootstrap().catch(error => {
|
|
15
|
+
logger.error('Error during startup:', error)
|
|
16
|
+
// A bot that never came online is a failed start: exit non-zero, so Docker, systemd or CI see it.
|
|
17
|
+
process.exitCode = 1
|
|
18
|
+
})
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
},
|
|
26
26
|
"types": ["node"]
|
|
27
27
|
},
|
|
28
|
-
"include": ["src/**/*.ts"],
|
|
29
|
-
"exclude": ["
|
|
28
|
+
"include": ["src/**/*.ts", "meocord.config.ts"],
|
|
29
|
+
"exclude": ["dist", "vitest.config.ts", "node_modules", "src/**/*.spec.ts"]
|
|
30
30
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MessageHandler, Controller
|
|
2
|
-
import {
|
|
1
|
+
import { MessageHandler, Controller } from 'meocord/decorator'
|
|
2
|
+
import { Message } from 'discord.js'
|
|
3
3
|
import { Logger } from 'meocord/common'
|
|
4
4
|
|
|
5
5
|
@Controller()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { MessageReaction
|
|
1
|
+
import { MessageReaction } from 'discord.js'
|
|
2
2
|
import { Controller, ReactionHandler } from 'meocord/decorator'
|
|
3
3
|
import { Logger } from 'meocord/common'
|
|
4
|
-
import {
|
|
4
|
+
import { ReactionHandlerAction } from 'meocord/enum'
|
|
5
5
|
import { type ReactionHandlerOptions } from 'meocord/interface'
|
|
6
6
|
|
|
7
7
|
@Controller()
|
|
@@ -10,12 +10,12 @@ export class {{className}}ReactionController {
|
|
|
10
10
|
|
|
11
11
|
@ReactionHandler('😋')
|
|
12
12
|
async handleReaction(reaction: MessageReaction, { user, action }: ReactionHandlerOptions) {
|
|
13
|
-
this.logger.log(`Reaction 😋 ${action === ReactionHandlerAction.ADD ? 'added' : 'removed'}.`)
|
|
13
|
+
this.logger.log(`Reaction 😋 ${action === ReactionHandlerAction.ADD ? 'added' : 'removed'}.`)
|
|
14
14
|
|
|
15
|
-
if (!reaction.message) return
|
|
15
|
+
if (!reaction.message) return
|
|
16
16
|
|
|
17
17
|
if (action === ReactionHandlerAction.ADD) {
|
|
18
|
-
await reaction.message.reply(`${user.username} reacted with 😋!`)
|
|
18
|
+
await reaction.message.reply(`${user.username} reacted with 😋!`)
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Guard } from 'meocord/decorator'
|
|
2
|
-
import { GuardInterface } from 'meocord/interface'
|
|
2
|
+
import { type GuardInterface } from 'meocord/interface'
|
|
3
3
|
import { BaseInteraction, Message, MessageReaction } from 'discord.js'
|
|
4
4
|
|
|
5
5
|
@Guard()
|
|
6
6
|
export class {{className}}Guard implements GuardInterface {
|
|
7
|
-
async canActivate(
|
|
7
|
+
async canActivate(_context: BaseInteraction | Message | MessageReaction): Promise<boolean> {
|
|
8
8
|
// TODO: Implement the guard logic to determine if the interaction is allowed
|
|
9
9
|
return true
|
|
10
10
|
}
|
|
@@ -88,28 +88,30 @@ class MeoCordApp {
|
|
|
88
88
|
}
|
|
89
89
|
return this.controllerInstancesCache.get(controllerClass);
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Registers the Discord event handlers and logs in.
|
|
93
|
+
*
|
|
94
|
+
* Rejects when the login fails -- an invalid token, or Discord unreachable -- so the caller can
|
|
95
|
+
* stop with a non-zero exit code. A bot that never came online is a failed start, and a
|
|
96
|
+
* supervisor such as Docker's `restart: on-failure` or systemd can only tell if the process says so.
|
|
97
|
+
*/ async start() {
|
|
98
|
+
this.logger.log('Starting bot...');
|
|
99
|
+
this.bot.on('clientReady', ()=>this.runListener('clientReady', async ()=>{
|
|
100
|
+
this.activityInterval = setInterval(()=>this.updateActivity(), 10000);
|
|
101
|
+
await this.registerCommands();
|
|
102
|
+
}));
|
|
103
|
+
this.bot.on('interactionCreate', (interaction)=>this.runListener('interactionCreate', ()=>this.handleInteraction(interaction)));
|
|
104
|
+
this.bot.on('messageCreate', (message)=>this.runListener('messageCreate', ()=>this.handleMessage(message)));
|
|
105
|
+
this.bot.on('messageReactionAdd', (reaction, user)=>this.runListener('messageReactionAdd', ()=>this.handleReaction(reaction, {
|
|
106
|
+
user,
|
|
107
|
+
action: ReactionHandlerAction.ADD
|
|
108
|
+
})));
|
|
109
|
+
this.bot.on('messageReactionRemove', (reaction, user)=>this.runListener('messageReactionRemove', ()=>this.handleReaction(reaction, {
|
|
110
|
+
user,
|
|
111
|
+
action: ReactionHandlerAction.REMOVE
|
|
112
|
+
})));
|
|
113
|
+
await this.bot.login(this.discordToken);
|
|
114
|
+
this.logger.log('Bot is online!');
|
|
113
115
|
}
|
|
114
116
|
async registerCommands() {
|
|
115
117
|
// Keyed by type and name together, because that pair is what Discord treats as one
|
package/dist/esm/package.json.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ColorResolvable } from 'discord.js';
|
|
2
|
+
|
|
3
|
+
declare class Logger {
|
|
4
|
+
private context?;
|
|
5
|
+
private readonly colorMap;
|
|
6
|
+
constructor(context?: string | undefined);
|
|
7
|
+
log(...args: any[]): void;
|
|
8
|
+
info(...args: any[]): void;
|
|
9
|
+
warn(...args: any[]): void;
|
|
10
|
+
error(...args: any[]): void;
|
|
11
|
+
debug(...args: any[]): void;
|
|
12
|
+
verbose(...args: any[]): void;
|
|
13
|
+
private formatMessage;
|
|
14
|
+
private logWithContext;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare class Theme {
|
|
18
|
+
static successColor: ColorResolvable;
|
|
19
|
+
static infoColor: ColorResolvable;
|
|
20
|
+
static errorColor: ColorResolvable;
|
|
21
|
+
static warningColor: ColorResolvable;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Composes multiple class or method decorators into a single decorator.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* export const Protected = () => applyDecorators(
|
|
30
|
+
* UseGuard(DefaultGuard, GlobalRateLimiterGuard),
|
|
31
|
+
* )
|
|
32
|
+
*
|
|
33
|
+
* @Controller()
|
|
34
|
+
* @Protected()
|
|
35
|
+
* export class PingController {}
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare function applyDecorators(...decorators: (ClassDecorator | MethodDecorator)[]): ClassDecorator & MethodDecorator;
|
|
39
|
+
/**
|
|
40
|
+
* Attaches arbitrary metadata to a class or method. Use alongside `Reflect.getMetadata` to read it back.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* export const Roles = (...roles: string[]) => SetMetadata('roles', roles)
|
|
45
|
+
*
|
|
46
|
+
* @Command('admin', CommandType.SLASH)
|
|
47
|
+
* @Roles('admin', 'moderator')
|
|
48
|
+
* async adminCommand(interaction: ChatInputCommandInteraction) {}
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare function SetMetadata<V = any>(metadataKey: string, metadataValue: V): ClassDecorator & MethodDecorator;
|
|
52
|
+
|
|
53
|
+
export { Logger, SetMetadata, Theme, applyDecorators };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kinds of interaction a `@Command` method can be bound to.
|
|
3
|
+
*
|
|
4
|
+
* Each member names one Discord interaction shape rather than a family of them, so a
|
|
5
|
+
* handler's parameter type follows from its command type alone. That is why the four
|
|
6
|
+
* entity select menus are separate members instead of one `SELECT_MENU`: Discord sends
|
|
7
|
+
* them as distinct component types (5-8) carrying different resolved data, and
|
|
8
|
+
* collapsing them would leave the handler with a union it has to re-narrow by hand.
|
|
9
|
+
*/
|
|
10
|
+
declare enum CommandType {
|
|
11
|
+
/** Chat input command, or one subcommand of it. */
|
|
12
|
+
SLASH = "SLASH",
|
|
13
|
+
/** User or message context menu command. */
|
|
14
|
+
CONTEXT_MENU = "CONTEXT_MENU",
|
|
15
|
+
/** Activity launch command (`ApplicationCommandType.PrimaryEntryPoint`). */
|
|
16
|
+
PRIMARY_ENTRY_POINT = "PRIMARY_ENTRY_POINT",
|
|
17
|
+
BUTTON = "BUTTON",
|
|
18
|
+
/** String select menu — the one whose options the application defines itself. */
|
|
19
|
+
SELECT_MENU = "SELECT_MENU",
|
|
20
|
+
USER_SELECT_MENU = "USER_SELECT_MENU",
|
|
21
|
+
ROLE_SELECT_MENU = "ROLE_SELECT_MENU",
|
|
22
|
+
MENTIONABLE_SELECT_MENU = "MENTIONABLE_SELECT_MENU",
|
|
23
|
+
CHANNEL_SELECT_MENU = "CHANNEL_SELECT_MENU",
|
|
24
|
+
MODAL_SUBMIT = "MODAL_SUBMIT"
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Enum representing actions that can be performed on a message reaction.
|
|
28
|
+
*/
|
|
29
|
+
declare enum ReactionHandlerAction {
|
|
30
|
+
/** Reaction added to a message. */
|
|
31
|
+
ADD = "ADD",
|
|
32
|
+
/** Reaction removed from a message. */
|
|
33
|
+
REMOVE = "REMOVE"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { CommandType as C, ReactionHandlerAction as R };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Container, ServiceIdentifier } from 'inversify';
|
|
2
|
+
import { Client, ActivityOptions } from 'discord.js';
|
|
3
|
+
|
|
4
|
+
declare class MeoCordApp {
|
|
5
|
+
private readonly controllerClasses;
|
|
6
|
+
private readonly container;
|
|
7
|
+
private readonly discordClient;
|
|
8
|
+
private discordToken;
|
|
9
|
+
private activities?;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly bot;
|
|
12
|
+
private isShuttingDown;
|
|
13
|
+
private activityInterval;
|
|
14
|
+
private controllerInstancesCache;
|
|
15
|
+
constructor(controllerClasses: (new (...args: any[]) => any)[], container: Container, discordClient: Client, discordToken: string, activities?: ActivityOptions[] | undefined);
|
|
16
|
+
/**
|
|
17
|
+
* Runs an event handler so a failure inside it cannot take the process down.
|
|
18
|
+
*
|
|
19
|
+
* discord.js calls listeners without awaiting them, so a rejection escaping one has
|
|
20
|
+
* nothing left to settle it: Node reports an unhandled rejection, which terminates
|
|
21
|
+
* the process by default. Losing the whole bot because one reaction landed on a
|
|
22
|
+
* deleted message, or one controller could not be resolved, is a worse failure than
|
|
23
|
+
* the one that caused it -- every other user is served by the same process.
|
|
24
|
+
*
|
|
25
|
+
* Nothing is silenced. The error is logged against the event that produced it, so a
|
|
26
|
+
* genuine misconfiguration -- an unbound controller, a missing dependency -- shows
|
|
27
|
+
* up on the very first interaction rather than staying hidden.
|
|
28
|
+
*
|
|
29
|
+
* @param event - The gateway event being handled, named in the log.
|
|
30
|
+
* @param run - The handler to run.
|
|
31
|
+
*/
|
|
32
|
+
private runListener;
|
|
33
|
+
/**
|
|
34
|
+
* Rotates the bot's activity.
|
|
35
|
+
*
|
|
36
|
+
* Guarded separately from {@link runListener}: this runs on a timer rather than an
|
|
37
|
+
* event, and a throw from a timer callback is an uncaught exception no listener
|
|
38
|
+
* wrapper can reach.
|
|
39
|
+
*/
|
|
40
|
+
private updateActivity;
|
|
41
|
+
private getInstance;
|
|
42
|
+
/**
|
|
43
|
+
* Registers the Discord event handlers and logs in.
|
|
44
|
+
*
|
|
45
|
+
* Rejects when the login fails -- an invalid token, or Discord unreachable -- so the caller can
|
|
46
|
+
* stop with a non-zero exit code. A bot that never came online is a failed start, and a
|
|
47
|
+
* supervisor such as Docker's `restart: on-failure` or systemd can only tell if the process says so.
|
|
48
|
+
*/
|
|
49
|
+
start(): Promise<void>;
|
|
50
|
+
registerCommands(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Every pattern-matched route, ordered most specific first.
|
|
53
|
+
*
|
|
54
|
+
* Built once and cached, so dispatch stays a single ordered walk with an early exit
|
|
55
|
+
* rather than paying to rank anything per interaction. Ordering here is what lets
|
|
56
|
+
* `gi-profile/summary/{ownerId}/{uid}` keep the ids it owns when
|
|
57
|
+
* `gi-profile/{uuid}/{uid}` would also match them — without it, the winner would be
|
|
58
|
+
* whichever controller happened to be registered first.
|
|
59
|
+
*/
|
|
60
|
+
private componentRoutes?;
|
|
61
|
+
private getComponentRoutes;
|
|
62
|
+
/**
|
|
63
|
+
* Warns rather than throws: an app whose patterns overlap boots and works today, and
|
|
64
|
+
* refusing to start would turn a latent mis-route into an outage on upgrade.
|
|
65
|
+
*/
|
|
66
|
+
private reportAmbiguousRoutes;
|
|
67
|
+
/**
|
|
68
|
+
* Every `@Autocomplete` handler, ordered so an option-specific handler is found
|
|
69
|
+
* before a command-wide one.
|
|
70
|
+
*
|
|
71
|
+
* Cached alongside the component table: autocomplete fires on every keystroke, and
|
|
72
|
+
* rebuilding the list per keystroke would put reflection on the hottest path the
|
|
73
|
+
* framework has.
|
|
74
|
+
*/
|
|
75
|
+
private autocompleteRoutes?;
|
|
76
|
+
private getAutocompleteRoutes;
|
|
77
|
+
/**
|
|
78
|
+
* Dispatches an interaction, and makes sure a failure anywhere in that still reaches
|
|
79
|
+
* the person who triggered it.
|
|
80
|
+
*
|
|
81
|
+
* {@link executeCommand} already reports what a handler throws, but everything
|
|
82
|
+
* *before* the handler can fail too — resolving a controller through the container
|
|
83
|
+
* is the common case — and a component that fails there would otherwise look dead
|
|
84
|
+
* with nothing said to the user and nothing in the log.
|
|
85
|
+
*/
|
|
86
|
+
private handleInteraction;
|
|
87
|
+
private dispatchInteraction;
|
|
88
|
+
/**
|
|
89
|
+
* The names a command interaction can be handled under, most specific first.
|
|
90
|
+
*
|
|
91
|
+
* Empty for anything that is not a registered command, which is how a component
|
|
92
|
+
* whose customId matched no pattern falls through to the unmatched warning instead
|
|
93
|
+
* of being looked up under a name it does not have.
|
|
94
|
+
*/
|
|
95
|
+
private resolveNameRoutes;
|
|
96
|
+
/**
|
|
97
|
+
* Answers an autocomplete interaction from the `@Autocomplete` handler that claims it.
|
|
98
|
+
*
|
|
99
|
+
* Discord closes the window after three seconds and shows a loading state until
|
|
100
|
+
* something arrives, so an unclaimed option is answered with an empty list rather
|
|
101
|
+
* than left to time out -- a visibly empty menu is a better failure than a stuck one,
|
|
102
|
+
* and the warning says which option is missing a handler.
|
|
103
|
+
*/
|
|
104
|
+
private handleAutocomplete;
|
|
105
|
+
/** Closes an autocomplete window that nothing else answered. */
|
|
106
|
+
private respondEmpty;
|
|
107
|
+
/**
|
|
108
|
+
* Runs a resolved command, shared by both dispatch paths so a pattern-matched
|
|
109
|
+
* component and a named slash command behave identically once the route is chosen.
|
|
110
|
+
*/
|
|
111
|
+
private executeCommand;
|
|
112
|
+
/**
|
|
113
|
+
* Tells the user something went wrong, if the interaction can still hear it.
|
|
114
|
+
*
|
|
115
|
+
* A handler that replies and *then* throws is the common shape of a failure, and
|
|
116
|
+
* replying twice throws in turn -- out of the catch block, where nothing is left to
|
|
117
|
+
* handle it. Whatever the interaction's state, reporting an error must not be able
|
|
118
|
+
* to become a second, worse one.
|
|
119
|
+
*/
|
|
120
|
+
private replyWithError;
|
|
121
|
+
private handleMessage;
|
|
122
|
+
private handleReaction;
|
|
123
|
+
private gracefulShutdown;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
declare class MeoCordFactory {
|
|
127
|
+
private static logger;
|
|
128
|
+
static create(target: ServiceIdentifier): MeoCordApp;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export { MeoCordFactory };
|
|
@@ -39,6 +39,13 @@ declare class MeoCordApp {
|
|
|
39
39
|
*/
|
|
40
40
|
private updateActivity;
|
|
41
41
|
private getInstance;
|
|
42
|
+
/**
|
|
43
|
+
* Registers the Discord event handlers and logs in.
|
|
44
|
+
*
|
|
45
|
+
* Rejects when the login fails -- an invalid token, or Discord unreachable -- so the caller can
|
|
46
|
+
* stop with a non-zero exit code. A bot that never came online is a failed start, and a
|
|
47
|
+
* supervisor such as Docker's `restart: on-failure` or systemd can only tell if the process says so.
|
|
48
|
+
*/
|
|
42
49
|
start(): Promise<void>;
|
|
43
50
|
registerCommands(): Promise<void>;
|
|
44
51
|
/**
|