Skip to content

Commit e563176

Browse files
committed
fix: legacy event handler behavior
1 parent 767939f commit e563176

File tree

5 files changed

+110
-2
lines changed

5 files changed

+110
-2
lines changed

apps/website/docs/guide/06-plugins/03-creating-a-runtime-plugin.mdx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,35 @@ async onEventsRouterInit(ctx: CommandKitPluginRuntime): Promise<void> {
183183
}
184184
```
185185
186+
## Event handler hooks
187+
188+
These hooks are called when processing events.
189+
190+
#### `willEmitEvent(ctx, event)`
191+
192+
Called before an event is emitted.
193+
194+
**Parameters:**
195+
196+
- `ctx`: The runtime context.
197+
- `event`: The event object being emitted.
198+
199+
**Example use case:** Modify event data before it's emitted, or cancel the event.
200+
201+
```typescript
202+
async willEmitEvent(
203+
ctx: CommandKitPluginRuntime,
204+
event: CommandKitEventDispatch
205+
): Promise<void> {
206+
// prevent other plugins from handling this event
207+
event.accept();
208+
// Modify event data
209+
event.args.push('This is a custom argument');
210+
}
211+
```
212+
213+
Now the event listener will receive the modified event data.
214+
186215
## Command Registration Hooks
187216
188217
These hooks are called during the command registration process, allowing you to modify commands before they're registered with Discord.

packages/commandkit/src/app/handlers/AppEventsHandler.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { toFileURL } from '../../utils/resolve-file-url';
66
import { StopEventPropagationError } from '../../utils/utilities';
77
import { runInEventWorkerContext } from '../events/EventWorkerContext';
88
import { ParsedEvent } from '../router';
9+
import { CommandKitEventDispatch } from '../../plugins';
910

1011
export type EventListener = {
1112
handler: ListenerFunction;
@@ -133,6 +134,27 @@ export class AppEventsHandler {
133134

134135
// Create main handler for regular "on" listeners
135136
const mainHandler: ListenerFunction = async (...args) => {
137+
let accepted = false;
138+
139+
const event: CommandKitEventDispatch = {
140+
name,
141+
args,
142+
namespace: namespace ?? null,
143+
once: false,
144+
metadata: data.event,
145+
accept() {
146+
if (accepted) return;
147+
accepted = true;
148+
},
149+
};
150+
151+
await this.commandkit.plugins
152+
.execute(async (ctx, plugin) => {
153+
if (accepted) return;
154+
return plugin.willEmitEvent?.(ctx, event);
155+
})
156+
.catch(Object);
157+
136158
await runInEventWorkerContext(
137159
{
138160
event: name,
@@ -172,6 +194,26 @@ export class AppEventsHandler {
172194
// Create handler for "once" listeners with cleanup logic
173195
const onceHandler: ListenerFunction = async (...args) => {
174196
let broken = false;
197+
let accepted = false;
198+
199+
const event: CommandKitEventDispatch = {
200+
name,
201+
args,
202+
namespace: namespace ?? null,
203+
once: true,
204+
metadata: data.event,
205+
accept() {
206+
if (accepted) return;
207+
accepted = true;
208+
},
209+
};
210+
211+
await this.commandkit.plugins
212+
.execute(async (ctx, plugin) => {
213+
if (accepted) return;
214+
return plugin.willEmitEvent?.(ctx, event);
215+
})
216+
.catch(Object);
175217

176218
for (const listener of onceListeners) {
177219
if (broken) break; // Stop executing remaining listeners if propagation was stopped

packages/commandkit/src/plugins/RuntimePlugin.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Interaction, Message, PartialMessage } from 'discord.js';
1+
import { Interaction, Message } from 'discord.js';
22
import {
33
isPlugin,
44
PluginCommon,
@@ -10,6 +10,7 @@ import { CommandBuilderLike, PreparedAppCommandExecution } from '../app';
1010
import { CommandKitEnvironment } from '../context/environment';
1111
import { CommandKitHMREvent } from '../utils/dev-hooks';
1212
import { PreRegisterCommandsEvent } from '../app/register/CommandRegistrar';
13+
import { CommandKitEventDispatch } from './types';
1314

1415
export abstract class RuntimePlugin<
1516
T extends PluginOptions = PluginOptions,
@@ -179,6 +180,16 @@ export abstract class RuntimePlugin<
179180
ctx: CommandKitPluginRuntime,
180181
env: CommandKitEnvironment,
181182
) {}
183+
184+
/**
185+
* Called before emitting an event
186+
* @param ctx The context
187+
* @param event The event that is being emitted
188+
*/
189+
public async willEmitEvent(
190+
ctx: CommandKitPluginRuntime,
191+
event: CommandKitEventDispatch,
192+
) {}
182193
}
183194

184195
export function isRuntimePlugin(plugin: unknown): plugin is RuntimePlugin {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
import { ParsedEvent } from '../app/router';
12
import type { CompilerPlugin } from './CompilerPlugin';
23
import type { RuntimePlugin } from './RuntimePlugin';
34

45
export type CommandKitPlugin = RuntimePlugin | CompilerPlugin;
56
export type MaybeFalsey<T> = T | false | null | undefined;
7+
8+
export interface CommandKitEventDispatch {
9+
name: string;
10+
args: unknown[];
11+
namespace: string | null;
12+
once: boolean;
13+
metadata: ParsedEvent;
14+
accept(): void;
15+
}

packages/legacy/src/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import {
1212
CommandKitHMREvent,
1313
HMREventType,
1414
getSourceDirectories,
15+
CommandKitEventDispatch,
1516
} from 'commandkit';
16-
import { join } from 'node:path';
17+
import { join, resolve } from 'node:path';
1718
import { loadLegacyValidations } from './loadLegacyValidations.js';
1819
import { CommandData, loadLegacyCommands } from './loadLegacyCommands.js';
1920
import { existsSync } from 'node:fs';
@@ -107,6 +108,21 @@ export class LegacyHandlerPlugin extends RuntimePlugin<LegacyHandlerPluginOption
107108
await this.loadCommands(ctx, middlewareIds);
108109
}
109110

111+
public async willEmitEvent(
112+
ctx: CommandKitPluginRuntime,
113+
event: CommandKitEventDispatch,
114+
): Promise<void> {
115+
const eventPath = resolve(event.metadata.path);
116+
const ourPath = resolve(this.options.eventsPath);
117+
118+
if (!eventPath.startsWith(ourPath)) return;
119+
120+
event.accept();
121+
122+
// legacy handler injects the client to the last argument
123+
event.args.push(ctx.commandkit.client);
124+
}
125+
110126
private async loadCommands(
111127
ctx: CommandKitPluginRuntime,
112128
middlewareIds: string[],

0 commit comments

Comments
 (0)