GlyriaBus
Overview
GlyriaBus is a typed pub/sub event bus with middleware support. It lets you communicate between different parts of your bot without coupling them together.
// src/utils/useBus.ts
type BotEvents = {
userBanned: [guildId: string, userId: string, reason: string]
levelUp: [userId: string, level: number]
}
export const useBus = new GlyriaBus<BotEvents>()
GlyriaBus is available globally — no import needed. Define your bus in src/utils/ and it's auto-imported everywhere.Constructor
new GlyriaBus<Events>()
Type parameter
Events is a record mapping event names to their payload types (as tuples):
type Events = {
userBanned: [guildId: string, userId: string]
levelUp: [userId: string, level: number]
}
Methods
.on(event, listener)
Register a listener for an event. Returns an unregister function.
const stop = useBus.on("userBanned", (guildId, userId) => {
console.log(`${userId} banned from ${guildId}`)
})
// later
stop()
| Parameter | Type | Description |
|---|---|---|
event | keyof Events | Event name |
listener | Listener<Events[K]> | Handler receiving the event payload |
Returns () => void — call it to remove the listener.
.use(event, middleware)
Register a middleware for an event. Middlewares run before listeners and must call next() to continue the chain.
useBus.use("userBanned", async (guildId, userId, next) => {
console.log(`[middleware] ban received`)
await next()
})
| Parameter | Type | Description |
|---|---|---|
event | keyof Events | Event name |
middleware | Middleware<Events[K]> | Handler with next as last argument |
.emit(event, ...args)
Emit an event with typed arguments. Runs all middlewares and listeners in order.
await useBus.emit("userBanned", guildId, userId, reason)
| Parameter | Type | Description |
|---|---|---|
event | keyof Events | Event name |
...args | Events[K] | Typed event payload |
Returns Promise<void>
.off(event, middleware)
Remove a specific middleware from an event.
useBus.off("userBanned", myMiddleware)
.clear(event)
Remove all listeners and middlewares for an event.
useBus.clear("userBanned")
Types
Middleware<T>
type Middleware<T extends any[]> = (
...args: [...ctx: T, next: NextFunction]
) => any | Promise<any>
Listener<T>
type Listener<T extends any[]> = (...ctx: T) => any | Promise<any>
NextFunction
type NextFunction = () => void | Promise<void>
Middleware chain
Middlewares and listeners run in registration order. Not calling next() stops the chain — subsequent middlewares and listeners won't run.
useBus.use("levelUp", async (userId, level, next) => {
if (level < 5) return // stops here, listener never runs
await next()
})
useBus.on("levelUp", (userId, level) => {
console.log(`${userId} reached level ${level}`)
})

