discordthing 0.1.0 → 0.1.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 CHANGED
@@ -17,105 +17,63 @@ pnpm add discordthing
17
17
  ## Create a bot
18
18
 
19
19
  ```ts
20
- import { createBot, createCommandExecutor, okMessage } from "discordthing";
21
- import { EmbedBuilder, Colors } from "discord.js";
22
-
23
- import { commands } from "./commands";
24
- import { eventListeners } from "./eventListeners";
25
-
26
- const commandExecutor = createCommandExecutor({
27
- getErrorMessage(msg, _err, _interaction) {
28
- const embed = new EmbedBuilder()
29
- .setColor(Colors.Red)
30
- .setTitle(":warning: Error")
31
- .setDescription(msg);
32
-
33
- return okMessage({
34
- embeds: [embed]
35
- });
36
- }
37
- });
20
+ import { Bot } from "discordthing";
38
21
 
39
- const client = createBot({
40
- clientOptions: {
41
- intents: ["Guilds", "GuildMembers"]
22
+ import { myCommand } from "./say.command";
23
+ import { myListener } from "./welcome.event";
24
+
25
+ const bot = new Bot(
26
+ {
27
+ name: "My bot",
28
+ commands: [myCommand],
29
+ listeners: [myListener]
42
30
  },
43
- commandExecutor,
44
- commands,
45
- eventListeners
46
- });
31
+ {
32
+ intents: ["Guilds", "GuildMembers"]
33
+ }
34
+ );
47
35
 
48
- client.login(process.env.DISCORD_TOKEN);
36
+ await bot.start(process.env.DISCORD_BOT_TOKEN);
49
37
  ```
50
38
 
51
39
  ### Define a command
52
40
 
53
41
  ```ts
54
- // hello-world.command.ts
42
+ // say.command.ts
55
43
 
56
- import { defineCommand } from "discordthing";
57
- import { Result } from "@l3dev/result";
44
+ import { command } from "discordthing/commands";
45
+ import { o } from "discordthing/options";
46
+ import { NONE } from "@l3dev/result";
58
47
 
59
- export default defineCommand({
60
- name: "hello-world",
61
- define(builder) {
62
- return builder.setName(this.name).setDescription("Say hello!");
48
+ export const myCommand = command({
49
+ meta: {
50
+ name: "say"
51
+ },
52
+ options: {
53
+ message: o.string().describe("The message to say")
63
54
  },
64
- async execute(interaction) {
65
- return await Result.fromPromise(
66
- { onError: { type: "HELLO_WORLD_REPLY" } },
67
- interaction.reply("Hello world!")
68
- );
55
+ async handler(ctx, args) {
56
+ await ctx.interaction.reply(args.message);
57
+
58
+ return NONE;
69
59
  }
70
60
  });
71
61
  ```
72
62
 
73
- Export commands as a single object:
74
-
75
- ```ts
76
- // commands.ts
77
-
78
- export const commands = {
79
- helloWorld: await import("./hello-world.command")
80
- };
81
-
82
- // or if you are using a bundler like Vite:
83
-
84
- export const commands = import.meta.glob<true, string>("./*.command.ts", { eager: true });
85
- ```
86
-
87
63
  ### Define an event listener
88
64
 
89
65
  ```ts
90
66
  // welcome.event.ts
91
67
 
92
- import { defineEventListener } from "@l3dev/discord.js-helpers";
93
- import { Result } from "@l3dev/result";
68
+ import { listen } from "discordthing/events";
94
69
  import { Events } from "discord.js";
95
70
 
96
- export default defineEventListener({
71
+ export const myListener = listen({
97
72
  event: Events.GuildMemberAdd,
98
- async listener(member) {
73
+ async handler(member) {
99
74
  const joinChannel = await getJoinChannel(member.guild);
100
75
 
101
- return await Result.fromPromise(
102
- { onError: { type: "WELCOME_MESSAGE" } },
103
- joinChannel.send(`Welcome <@${member.user.id}>!`)
104
- );
76
+ await joinChannel.send(`Welcome <@${member.user.id}>!`);
105
77
  }
106
78
  });
107
79
  ```
108
-
109
- Export event listeners as a single object:
110
-
111
- ```ts
112
- // eventListeners.ts
113
-
114
- export const eventListeners = {
115
- welcome: await import("./welcome.event")
116
- };
117
-
118
- // or if you are using a bundler like Vite:
119
-
120
- export const eventListeners = import.meta.glob<true, string>("./*.event.ts", { eager: true });
121
- ```
package/build/bot.d.ts CHANGED
@@ -20,7 +20,7 @@ export declare class Bot {
20
20
  private readonly commandFilters;
21
21
  private readonly readyListeners;
22
22
  private readonly logger;
23
- constructor(clientOptions: ClientOptions, options?: BotOptions);
23
+ constructor(options: BotOptions, clientOptions: ClientOptions);
24
24
  addCommands(...commands: RestOrArray<Command<string, SlashCommandBuilder>>): void;
25
25
  addCommand(command: Command<string, SlashCommandBuilder>): void;
26
26
  addCommandFilter(filter: CommandFilter): void;
package/build/bot.js CHANGED
@@ -14,7 +14,7 @@ export class Bot {
14
14
  commandFilters = [];
15
15
  readyListeners = [];
16
16
  logger;
17
- constructor(clientOptions, options = {}) {
17
+ constructor(options, clientOptions) {
18
18
  this._rest = new REST({ version: "10" });
19
19
  this.client = new Client(clientOptions);
20
20
  this.plugins = (options.plugins ?? []).map((plugin) => plugin(options));
@@ -79,7 +79,12 @@ export class Bot {
79
79
  createListenerFn(listener) {
80
80
  return async (...args) => {
81
81
  const ctx = createContext(this, this.logger);
82
- listener.handler(ctx, ...args);
82
+ try {
83
+ await listener.handler(ctx, ...args);
84
+ }
85
+ catch (error) {
86
+ this.logger.error(`Error in listener ${listener.event}:`, error);
87
+ }
83
88
  };
84
89
  }
85
90
  async start(token) {
package/build/bot.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import { err, ok, Result, type ReturnResult } from \"@l3dev/result\";\nimport {\n\tClient,\n\tEvents,\n\tInteractionContextType,\n\tREST,\n\tSlashCommandBuilder,\n\ttype ClientOptions,\n\ttype Guild,\n\ttype Interaction,\n\ttype RestOrArray\n} from \"discord.js\";\nimport { Logger } from \"tslog\";\n\nimport type { Command, CommandCtx, CommandFilter } from \"./commands/command.js\";\nimport { CommandRegistration } from \"./commands/registration.js\";\nimport { createContext } from \"./context.js\";\nimport type { Listener } from \"./events/listener.js\";\nimport type { ILogger } from \"./logger.js\";\nimport type { Plugin, ResolvedPlugin } from \"./plugin.js\";\n\nexport type BotOptions = {\n\tname?: string;\n\tplugins?: Plugin[];\n\tcommands?: Command<string, SlashCommandBuilder>[];\n\tlisteners?: Listener<any>[];\n\tlogger?: ILogger;\n};\n\nexport class Bot {\n\treadonly client: Client<boolean>;\n\tprivate _rest: REST;\n\n\tget rest() {\n\t\treturn this._rest;\n\t}\n\n\tprivate readonly plugins: ResolvedPlugin[];\n\tprivate readonly commands: Record<string, Command<string, SlashCommandBuilder>>;\n\tprivate readonly commandFilters: CommandFilter[] = [];\n\tprivate readonly readyListeners: Listener<\"clientReady\">[] = [];\n\tprivate readonly logger: ILogger;\n\n\tconstructor(clientOptions: ClientOptions, options: BotOptions = {}) {\n\t\tthis._rest = new REST({ version: \"10\" });\n\t\tthis.client = new Client(clientOptions);\n\n\t\tthis.plugins = (options.plugins ?? []).map((plugin) => plugin(options));\n\t\tthis.logger =\n\t\t\toptions.logger ??\n\t\t\tnew Logger({\n\t\t\t\tname: options.name ?? \"discordthing-bot\"\n\t\t\t});\n\n\t\tfor (const plugin of this.plugins) {\n\t\t\tplugin.resolved(this);\n\t\t}\n\n\t\tthis.commands = [\n\t\t\t...(options.commands ?? []),\n\t\t\t...this.plugins.flatMap((plugin) => plugin.commands)\n\t\t].reduce(\n\t\t\t(acc, command) => ({\n\t\t\t\t...acc,\n\t\t\t\t[command.name]: command\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\n\t\tthis.client.on(Events.ClientReady, this.onReady.bind(this));\n\t\tthis.client.on(Events.InteractionCreate, this.onInteraction.bind(this));\n\n\t\tconst allListeners = [\n\t\t\t...(options.listeners ?? []),\n\t\t\t...this.plugins.flatMap((plugin) => plugin.listeners)\n\t\t];\n\t\tfor (const listener of allListeners) {\n\t\t\tif (listener.event === Events.ClientReady) {\n\t\t\t\tthis.readyListeners.push(listener);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.client.on(listener.event, this.createListenerFn(listener));\n\t\t}\n\t}\n\n\taddCommands(...commands: RestOrArray<Command<string, SlashCommandBuilder>>) {\n\t\tfor (const command of commands.flat()) {\n\t\t\tthis.addCommand(command);\n\t\t}\n\t}\n\n\taddCommand(command: Command<string, SlashCommandBuilder>) {\n\t\tif (this.client.isReady()) {\n\t\t\tthrow new Error(\"Cannot add command after bot has started\");\n\t\t}\n\n\t\tthis.commands[command.name] = command;\n\t}\n\n\taddCommandFilter(filter: CommandFilter) {\n\t\tthis.commandFilters.push(filter);\n\t}\n\n\taddListeners(...listeners: RestOrArray<Listener<any>>) {\n\t\tfor (const listener of listeners.flat()) {\n\t\t\tthis.addListener(listener);\n\t\t}\n\t}\n\n\taddListener(listener: Listener<any>) {\n\t\tif (this.client.isReady()) {\n\t\t\tthrow new Error(\"Cannot add listener after bot has started\");\n\t\t}\n\n\t\tif (listener.event === Events.ClientReady) {\n\t\t\tthis.readyListeners.push(listener);\n\t\t\treturn;\n\t\t}\n\n\t\t(listener.once ? this.client.once : this.client.on)(\n\t\t\tlistener.event,\n\t\t\tthis.createListenerFn(listener)\n\t\t);\n\t}\n\n\tprivate createListenerFn(listener: Listener<any>) {\n\t\treturn async (...args: any[]) => {\n\t\t\tconst ctx = createContext(this, this.logger);\n\t\t\tlistener.handler(ctx, ...args);\n\t\t};\n\t}\n\n\tasync start(token: string) {\n\t\tthis._rest = this._rest.setToken(token);\n\t\tawait this.client.login(token);\n\t}\n\n\tasync getMe(guild: Guild) {\n\t\tif (guild.members.me) {\n\t\t\treturn ok(guild.members.me);\n\t\t}\n\n\t\treturn await Result.fromPromise(guild.members.fetchMe(), {\n\t\t\tonError: { type: \"GET_ME\" }\n\t\t});\n\t}\n\n\tprivate async registerCommands(client: Client<true>) {\n\t\tconst commandRegistration = new CommandRegistration(this._rest, client);\n\n\t\tconst globalCommands = Object.values(this.commands).filter((command) => {\n\t\t\tconst contexts = command.getContexts();\n\t\t\treturn (\n\t\t\t\tcontexts.includes(InteractionContextType.BotDM) ||\n\t\t\t\tcontexts.includes(InteractionContextType.PrivateChannel)\n\t\t\t);\n\t\t});\n\n\t\tconst guildCommands = Object.values(this.commands).filter((command) => {\n\t\t\tconst contexts = command.getContexts();\n\t\t\treturn contexts.includes(InteractionContextType.Guild);\n\t\t});\n\n\t\tthis.logger.debug(`Registering global commands...`);\n\t\tawait commandRegistration.registerGlobalCommands(globalCommands);\n\n\t\tconst guilds = await client.guilds.fetch();\n\t\tfor (const guild of guilds.values()) {\n\t\t\tthis.logger.debug(`Registering guild commands for guild ${guild.id}...`);\n\t\t\tawait commandRegistration.registerGuildCommands(guild.id, guildCommands);\n\t\t}\n\t}\n\n\tprivate async onReady(client: Client<true>) {\n\t\tconst startMs = performance.now();\n\n\t\tawait this.registerCommands(client);\n\n\t\t// Make a copy so we can remove _once_ listeners\n\t\tconst listeners = [...this.readyListeners];\n\n\t\tfor (const listener of listeners) {\n\t\t\tconst handler = this.createListenerFn(listener);\n\t\t\thandler(client);\n\n\t\t\tif (listener.once) {\n\t\t\t\tconst index = this.readyListeners.indexOf(listener);\n\t\t\t\tif (index === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.readyListeners.splice(index, 1);\n\t\t\t}\n\t\t}\n\n\t\tconst endMs = performance.now();\n\t\tconst elapsedMs = endMs - startMs;\n\n\t\tthis.logger.info(\n\t\t\t`Ready! (${elapsedMs > 1000 ? `${(elapsedMs / 1000).toFixed(2)}s` : `${elapsedMs}ms`})`\n\t\t);\n\t}\n\n\tprivate async onInteraction(interaction: Interaction) {\n\t\tif (interaction.user.bot || !interaction.isChatInputCommand()) return;\n\n\t\tconst command = this.commands[interaction.commandName];\n\t\tif (!command) {\n\t\t\tthis.logger.error(`Unknown command '${interaction.commandName}'`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.commandFilters.some((filter) => filter(interaction, command))) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst ctx = createContext(this, this.logger) as CommandCtx;\n\t\tctx.interaction = interaction;\n\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await command.execute(ctx);\n\t\t} catch (error) {\n\t\t\tresult = err(\"COMMAND_FAILED\", {\n\t\t\t\tcommand: interaction.commandName,\n\t\t\t\tinteractionId: interaction.id,\n\t\t\t\terror\n\t\t\t});\n\t\t}\n\n\t\tconst unwrapped = Result.unwrap(result) as ReturnResult<any, any>;\n\t\tif (!unwrapped.ok) {\n\t\t\tthis.logger.error(`Error while executing command '${interaction.commandName}':`, result);\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import { err, ok, Result, type ReturnResult } from \"@l3dev/result\";\nimport {\n\tClient,\n\tEvents,\n\tInteractionContextType,\n\tREST,\n\tSlashCommandBuilder,\n\ttype ClientOptions,\n\ttype Guild,\n\ttype Interaction,\n\ttype RestOrArray\n} from \"discord.js\";\nimport { Logger } from \"tslog\";\n\nimport type { Command, CommandCtx, CommandFilter } from \"./commands/command.js\";\nimport { CommandRegistration } from \"./commands/registration.js\";\nimport { createContext } from \"./context.js\";\nimport type { Listener } from \"./events/listener.js\";\nimport type { ILogger } from \"./logger.js\";\nimport type { Plugin, ResolvedPlugin } from \"./plugin.js\";\n\nexport type BotOptions = {\n\tname?: string;\n\tplugins?: Plugin[];\n\tcommands?: Command<string, SlashCommandBuilder>[];\n\tlisteners?: Listener<any>[];\n\tlogger?: ILogger;\n};\n\nexport class Bot {\n\treadonly client: Client<boolean>;\n\tprivate _rest: REST;\n\n\tget rest() {\n\t\treturn this._rest;\n\t}\n\n\tprivate readonly plugins: ResolvedPlugin[];\n\tprivate readonly commands: Record<string, Command<string, SlashCommandBuilder>>;\n\tprivate readonly commandFilters: CommandFilter[] = [];\n\tprivate readonly readyListeners: Listener<\"clientReady\">[] = [];\n\tprivate readonly logger: ILogger;\n\n\tconstructor(options: BotOptions, clientOptions: ClientOptions) {\n\t\tthis._rest = new REST({ version: \"10\" });\n\t\tthis.client = new Client(clientOptions);\n\n\t\tthis.plugins = (options.plugins ?? []).map((plugin) => plugin(options));\n\t\tthis.logger =\n\t\t\toptions.logger ??\n\t\t\tnew Logger({\n\t\t\t\tname: options.name ?? \"discordthing-bot\"\n\t\t\t});\n\n\t\tfor (const plugin of this.plugins) {\n\t\t\tplugin.resolved(this);\n\t\t}\n\n\t\tthis.commands = [\n\t\t\t...(options.commands ?? []),\n\t\t\t...this.plugins.flatMap((plugin) => plugin.commands)\n\t\t].reduce(\n\t\t\t(acc, command) => ({\n\t\t\t\t...acc,\n\t\t\t\t[command.name]: command\n\t\t\t}),\n\t\t\t{}\n\t\t);\n\n\t\tthis.client.on(Events.ClientReady, this.onReady.bind(this));\n\t\tthis.client.on(Events.InteractionCreate, this.onInteraction.bind(this));\n\n\t\tconst allListeners = [\n\t\t\t...(options.listeners ?? []),\n\t\t\t...this.plugins.flatMap((plugin) => plugin.listeners)\n\t\t];\n\t\tfor (const listener of allListeners) {\n\t\t\tif (listener.event === Events.ClientReady) {\n\t\t\t\tthis.readyListeners.push(listener);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.client.on(listener.event, this.createListenerFn(listener));\n\t\t}\n\t}\n\n\taddCommands(...commands: RestOrArray<Command<string, SlashCommandBuilder>>) {\n\t\tfor (const command of commands.flat()) {\n\t\t\tthis.addCommand(command);\n\t\t}\n\t}\n\n\taddCommand(command: Command<string, SlashCommandBuilder>) {\n\t\tif (this.client.isReady()) {\n\t\t\tthrow new Error(\"Cannot add command after bot has started\");\n\t\t}\n\n\t\tthis.commands[command.name] = command;\n\t}\n\n\taddCommandFilter(filter: CommandFilter) {\n\t\tthis.commandFilters.push(filter);\n\t}\n\n\taddListeners(...listeners: RestOrArray<Listener<any>>) {\n\t\tfor (const listener of listeners.flat()) {\n\t\t\tthis.addListener(listener);\n\t\t}\n\t}\n\n\taddListener(listener: Listener<any>) {\n\t\tif (this.client.isReady()) {\n\t\t\tthrow new Error(\"Cannot add listener after bot has started\");\n\t\t}\n\n\t\tif (listener.event === Events.ClientReady) {\n\t\t\tthis.readyListeners.push(listener);\n\t\t\treturn;\n\t\t}\n\n\t\t(listener.once ? this.client.once : this.client.on)(\n\t\t\tlistener.event,\n\t\t\tthis.createListenerFn(listener)\n\t\t);\n\t}\n\n\tprivate createListenerFn(listener: Listener<any>) {\n\t\treturn async (...args: any[]) => {\n\t\t\tconst ctx = createContext(this, this.logger);\n\n\t\t\ttry {\n\t\t\t\tawait listener.handler(ctx, ...args);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logger.error(`Error in listener ${listener.event}:`, error);\n\t\t\t}\n\t\t};\n\t}\n\n\tasync start(token: string) {\n\t\tthis._rest = this._rest.setToken(token);\n\t\tawait this.client.login(token);\n\t}\n\n\tasync getMe(guild: Guild) {\n\t\tif (guild.members.me) {\n\t\t\treturn ok(guild.members.me);\n\t\t}\n\n\t\treturn await Result.fromPromise(guild.members.fetchMe(), {\n\t\t\tonError: { type: \"GET_ME\" }\n\t\t});\n\t}\n\n\tprivate async registerCommands(client: Client<true>) {\n\t\tconst commandRegistration = new CommandRegistration(this._rest, client);\n\n\t\tconst globalCommands = Object.values(this.commands).filter((command) => {\n\t\t\tconst contexts = command.getContexts();\n\t\t\treturn (\n\t\t\t\tcontexts.includes(InteractionContextType.BotDM) ||\n\t\t\t\tcontexts.includes(InteractionContextType.PrivateChannel)\n\t\t\t);\n\t\t});\n\n\t\tconst guildCommands = Object.values(this.commands).filter((command) => {\n\t\t\tconst contexts = command.getContexts();\n\t\t\treturn contexts.includes(InteractionContextType.Guild);\n\t\t});\n\n\t\tthis.logger.debug(`Registering global commands...`);\n\t\tawait commandRegistration.registerGlobalCommands(globalCommands);\n\n\t\tconst guilds = await client.guilds.fetch();\n\t\tfor (const guild of guilds.values()) {\n\t\t\tthis.logger.debug(`Registering guild commands for guild ${guild.id}...`);\n\t\t\tawait commandRegistration.registerGuildCommands(guild.id, guildCommands);\n\t\t}\n\t}\n\n\tprivate async onReady(client: Client<true>) {\n\t\tconst startMs = performance.now();\n\n\t\tawait this.registerCommands(client);\n\n\t\t// Make a copy so we can remove _once_ listeners\n\t\tconst listeners = [...this.readyListeners];\n\n\t\tfor (const listener of listeners) {\n\t\t\tconst handler = this.createListenerFn(listener);\n\t\t\thandler(client);\n\n\t\t\tif (listener.once) {\n\t\t\t\tconst index = this.readyListeners.indexOf(listener);\n\t\t\t\tif (index === -1) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.readyListeners.splice(index, 1);\n\t\t\t}\n\t\t}\n\n\t\tconst endMs = performance.now();\n\t\tconst elapsedMs = endMs - startMs;\n\n\t\tthis.logger.info(\n\t\t\t`Ready! (${elapsedMs > 1000 ? `${(elapsedMs / 1000).toFixed(2)}s` : `${elapsedMs}ms`})`\n\t\t);\n\t}\n\n\tprivate async onInteraction(interaction: Interaction) {\n\t\tif (interaction.user.bot || !interaction.isChatInputCommand()) return;\n\n\t\tconst command = this.commands[interaction.commandName];\n\t\tif (!command) {\n\t\t\tthis.logger.error(`Unknown command '${interaction.commandName}'`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.commandFilters.some((filter) => filter(interaction, command))) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst ctx = createContext(this, this.logger) as CommandCtx;\n\t\tctx.interaction = interaction;\n\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await command.execute(ctx);\n\t\t} catch (error) {\n\t\t\tresult = err(\"COMMAND_FAILED\", {\n\t\t\t\tcommand: interaction.commandName,\n\t\t\t\tinteractionId: interaction.id,\n\t\t\t\terror\n\t\t\t});\n\t\t}\n\n\t\tconst unwrapped = Result.unwrap(result) as ReturnResult<any, any>;\n\t\tif (!unwrapped.ok) {\n\t\t\tthis.logger.error(`Error while executing command '${interaction.commandName}':`, result);\n\t\t}\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ClientEvents } from "discord.js";
1
+ import { type ClientEvents } from "discord.js";
2
2
  import type { GenericCtx } from "../context.js";
3
3
  type ListenerHandler<Event extends keyof ClientEvents> = (ctx: GenericCtx, ...args: ClientEvents[Event]) => void | Promise<void>;
4
4
  export declare class Listener<Event extends keyof ClientEvents> {
@@ -7,7 +7,7 @@ export declare class Listener<Event extends keyof ClientEvents> {
7
7
  readonly once: boolean;
8
8
  constructor(event: Event, handler: ListenerHandler<Event>, once?: boolean);
9
9
  }
10
- export declare function listen<Event extends keyof ClientEvents>(listener: {
10
+ export declare function listen<const Event extends keyof ClientEvents>(listener: {
11
11
  /**
12
12
  * The type of discord event to listen to.
13
13
  */
@@ -19,6 +19,6 @@ export declare function listen<Event extends keyof ClientEvents>(listener: {
19
19
  /**
20
20
  * The handler for the event.
21
21
  */
22
- handler: (ctx: GenericCtx, ...args: ClientEvents[Event]) => void | Promise<void>;
22
+ handler: (ctx: GenericCtx, ...args: ClientEvents[NoInfer<Event>]) => void | Promise<void>;
23
23
  }): Listener<Event>;
24
24
  export {};
@@ -1,3 +1,4 @@
1
+ import {} from "discord.js";
1
2
  export class Listener {
2
3
  event;
3
4
  handler;
@@ -1 +1 @@
1
- {"version":3,"file":"listener.js","sourceRoot":"","sources":["../../src/events/listener.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,QAAQ;IAEV;IACA;IACA;IAHV,YACU,KAAY,EACZ,OAA+B,EAC/B,OAAgB,KAAK;QAFrB,UAAK,GAAL,KAAK,CAAO;QACZ,YAAO,GAAP,OAAO,CAAwB;QAC/B,SAAI,GAAJ,IAAI,CAAiB;IAC5B,CAAC;CACJ;AAED,MAAM,UAAU,MAAM,CAAmC,QAaxD;IACA,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC","sourcesContent":["import type { ClientEvents } from \"discord.js\";\n\nimport type { GenericCtx } from \"../context.js\";\n\ntype ListenerHandler<Event extends keyof ClientEvents> = (\n\tctx: GenericCtx,\n\t...args: ClientEvents[Event]\n) => void | Promise<void>;\n\nexport class Listener<Event extends keyof ClientEvents> {\n\tconstructor(\n\t\treadonly event: Event,\n\t\treadonly handler: ListenerHandler<Event>,\n\t\treadonly once: boolean = false\n\t) {}\n}\n\nexport function listen<Event extends keyof ClientEvents>(listener: {\n\t/**\n\t * The type of discord event to listen to.\n\t */\n\tevent: Event;\n\t/**\n\t * Whether the event should only be handled once.\n\t */\n\tonce?: boolean;\n\t/**\n\t * The handler for the event.\n\t */\n\thandler: (ctx: GenericCtx, ...args: ClientEvents[Event]) => void | Promise<void>;\n}) {\n\treturn new Listener(listener.event, listener.handler, listener.once);\n}\n"]}
1
+ {"version":3,"file":"listener.js","sourceRoot":"","sources":["../../src/events/listener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,MAAM,YAAY,CAAC;AAS/C,MAAM,OAAO,QAAQ;IAEV;IACA;IACA;IAHV,YACU,KAAY,EACZ,OAA+B,EAC/B,OAAgB,KAAK;QAFrB,UAAK,GAAL,KAAK,CAAO;QACZ,YAAO,GAAP,OAAO,CAAwB;QAC/B,SAAI,GAAJ,IAAI,CAAiB;IAC5B,CAAC;CACJ;AAED,MAAM,UAAU,MAAM,CAAyC,QAa9D;IACA,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC","sourcesContent":["import { type ClientEvents } from \"discord.js\";\n\nimport type { GenericCtx } from \"../context.js\";\n\ntype ListenerHandler<Event extends keyof ClientEvents> = (\n\tctx: GenericCtx,\n\t...args: ClientEvents[Event]\n) => void | Promise<void>;\n\nexport class Listener<Event extends keyof ClientEvents> {\n\tconstructor(\n\t\treadonly event: Event,\n\t\treadonly handler: ListenerHandler<Event>,\n\t\treadonly once: boolean = false\n\t) {}\n}\n\nexport function listen<const Event extends keyof ClientEvents>(listener: {\n\t/**\n\t * The type of discord event to listen to.\n\t */\n\tevent: Event;\n\t/**\n\t * Whether the event should only be handled once.\n\t */\n\tonce?: boolean;\n\t/**\n\t * The handler for the event.\n\t */\n\thandler: (ctx: GenericCtx, ...args: ClientEvents[NoInfer<Event>]) => void | Promise<void>;\n}) {\n\treturn new Listener(listener.event, listener.handler, listener.once);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discordthing",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A lightweight framework for building discord bots built on-top of discord.js",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",
@@ -38,6 +38,9 @@
38
38
  "type": "git",
39
39
  "url": "https://github.com/l3dotdev/discordthing.git"
40
40
  },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
41
44
  "peerDependencies": {
42
45
  "discord.js": "^14.25.0"
43
46
  },