@stelliajs/framework 1.3.0-dev-1 → 1.3.0

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
@@ -3,7 +3,7 @@
3
3
  ## About
4
4
 
5
5
  StelliaJS is built using Discord JS V14 and TypeScript. It allows you to quickly set up a new bot with a simple and complete architecture.
6
- A CLI is currently being developed and will soon be available for even greater convenience.
6
+ A CLI is available to help you set up a project with StelliaJS : [link to the CLI](https://github.com/StelliaJS/cli)
7
7
 
8
8
  ## Architecture
9
9
  Recommended architecture for StelliaJS project.
@@ -19,6 +19,10 @@ Recommended architecture for StelliaJS project.
19
19
  │ │ │ ├── ban.ts
20
20
  │ │ │ └── mute.ts
21
21
  │ │ └── ping.ts
22
+ │ ├── environments/
23
+ │ │ ├── environment.development.ts
24
+ │ │ ├── environment.model.ts
25
+ │ │ └── environment.ts
22
26
  │ ├── events/
23
27
  │ │ ├── ready.ts
24
28
  │ │ └── interactionCreate.ts
@@ -36,16 +40,17 @@ Recommended architecture for StelliaJS project.
36
40
  ├── .env
37
41
  ├── package.json
38
42
  ├── package-lock.json
43
+ ├── stellia.json
39
44
  └── tsconfig.json
40
45
  ```
46
+
41
47
  ## Examples
42
48
 
43
- ### Simple client
49
+ ### Simple client with environment
44
50
 
45
51
  ```js
46
52
  import { StelliaClient } from "@stelliajs/framework";
47
- import { GatewayIntentBits } from "discord-api-types/v10";
48
- import { Partials } from "discord.js";
53
+ import { GatewayIntentBits, Partials } from "discord.js";
49
54
 
50
55
  const client = new StelliaClient({
51
56
  intents: [
@@ -56,26 +61,31 @@ const client = new StelliaClient({
56
61
  ],
57
62
  partials: [Partials.Message, Partials.GuildMember]
58
63
  }, {
59
- autoCompletes: {
60
- directoryPath: "./interactions/autoCompletes"
61
- },
62
- buttons: {
63
- directoryPath: "./interactions/buttons"
64
- },
65
- commands: {
66
- directoryPath: "./commands/slash"
67
- },
68
- contextMenus: {
69
- directoryPath: "./commands/contextMenus"
70
- },
71
- events: {
72
- directoryPath: "./events"
73
- },
74
- modals: {
75
- directoryPath: "./interactions/modals"
64
+ managers: {
65
+ autoCompletes: {
66
+ directoryPath: "./interactions/autoCompletes"
67
+ },
68
+ buttons: {
69
+ directoryPath: "./interactions/buttons"
70
+ },
71
+ commands: {
72
+ directoryPath: "./commands/slash"
73
+ },
74
+ contextMenus: {
75
+ directoryPath: "./commands/contextMenus"
76
+ },
77
+ events: {
78
+ directoryPath: "./events"
79
+ },
80
+ modals: {
81
+ directoryPath: "./interactions/modals"
82
+ },
83
+ selectMenus: {
84
+ directoryPath: "./interactions/selectMenus"
85
+ }
76
86
  },
77
- selectMenus: {
78
- directoryPath: "./interactions/selectMenus"
87
+ environment: {
88
+ areGuildsConfigurationEnabled: true
79
89
  }
80
90
  });
81
91
 
@@ -84,34 +94,36 @@ await client.connect(process.env.TOKEN);
84
94
 
85
95
  ### Simple event
86
96
 
87
- #### Ready event
97
+ #### Ready event with environment
88
98
  ```js
89
99
  import { type StelliaClient, type EventStructure } from "@stelliajs/framework";
90
100
  import { Events } from "discord.js";
101
+ import { type CustomGuildsConfiguration } from "@environments/environment.model.ts";
91
102
 
92
103
  export default {
93
104
  data: {
94
105
  name: Events.ClientReady,
95
106
  once: true
96
107
  },
97
- async execute(client: StelliaClient<true>) { // <true> ensures that the client is Ready
108
+ async execute(client: StelliaClient<true>, environment: CustomGuildsConfiguration) { // <true> ensures that the client is Ready
98
109
  console.log(`Logged in as ${client.user.tag}`);
99
110
  await client.initializeCommands(); // Used to initialise registered commands
100
111
  }
101
112
  } as EventStructure;
102
113
  ```
103
114
 
104
- #### InteractionCreate event
115
+ #### InteractionCreate event with environment
105
116
  ```js
106
117
  import { type StelliaClient, type EventStructure } from "@stelliajs/framework";
107
118
  import { Events, type Interaction } from "discord.js";
119
+ import { type CustomGuildsConfiguration } from "@environments/environment.model.ts";
108
120
 
109
121
  export default {
110
122
  data: {
111
123
  name: Events.InteractionCreate,
112
124
  once: false
113
125
  },
114
- async execute(client: StelliaClient<true>, interaction: Interaction) {
126
+ async execute(client: StelliaClient<true>, environment: CustomGuildsConfiguration, interaction: Interaction) {
115
127
  if (interaction.inCachedGuild()) {
116
128
  await client.handleInteraction(interaction); // Automatic interaction handling
117
129
  }
@@ -124,11 +136,12 @@ export default {
124
136
  ```js
125
137
  import { type CommandStructure, ephemeralFollowUpResponse, type StelliaClient } from "@stelliajs/framework";
126
138
  import { type ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
139
+ import { type CustomGuildsConfiguration } from "@environments/environment.model.ts";
127
140
 
128
141
  export default {
129
142
  data: new SlashCommandBuilder()
130
143
  .setName("ping"),
131
- async execute(client: StelliaClient, interaction: ChatInputCommandInteraction<"cached">) { // All interactions are cached
144
+ async execute(client: StelliaClient, environment: CustomGuildsConfiguration, interaction: ChatInputCommandInteraction<"cached">) { // All interactions are cached
132
145
  await ephemeralFollowUpResponse(interaction, "Pong!", true); // Response is ephemeral and deleted after 60 seconds
133
146
  }
134
147
  } as CommandStructure;
@@ -1,14 +1,15 @@
1
1
  import { Client, type ClientOptions, type Interaction } from "discord.js";
2
2
  import { type ManagerOptions } from "../managers/index.js";
3
- import { type Environment, type EnvironmentConfiguration, type Managers } from "../typescript/index.js";
3
+ import { type ClientEnvironment, type GuildConfigurationType, type GuildsConfiguration, type Managers } from "../typescript/index.js";
4
4
  export declare class StelliaClient<Ready extends boolean = boolean> extends Client<Ready> {
5
5
  private readonly utils;
6
6
  readonly managers: Managers;
7
- readonly environment: Environment;
7
+ readonly environment: ClientEnvironment;
8
8
  constructor(clientOptions: ClientOptions, stelliaOptions?: StelliaOptions);
9
9
  connect: (token: string) => Promise<void>;
10
10
  initializeCommands: () => Promise<void>;
11
- getEnvironment: <CustomEnvironment extends EnvironmentConfiguration>() => Promise<CustomEnvironment>;
11
+ getGuildsConfiguration: <CustomGuildsConfiguration extends GuildsConfiguration>() => Promise<CustomGuildsConfiguration>;
12
+ getGuildConfiguration: (guildId: string) => GuildConfigurationType;
12
13
  handleInteraction: (interaction: Interaction<"cached">) => Promise<void>;
13
14
  private areManagersLoaded;
14
15
  private static convertFilePathToProduction;
@@ -23,6 +24,6 @@ interface StelliaOptions {
23
24
  selectMenus?: ManagerOptions;
24
25
  modals?: ManagerOptions;
25
26
  };
26
- environment?: Environment;
27
+ environment?: ClientEnvironment;
27
28
  }
28
29
  export {};
@@ -4,12 +4,16 @@ import { StelliaUtils } from "./index.js";
4
4
  import path from "path";
5
5
  import * as fs from "node:fs";
6
6
  import { pathToFileURL } from "url";
7
+ import { logger } from "../utils/logger.js";
7
8
  export class StelliaClient extends Client {
8
9
  utils;
9
10
  managers = {};
10
11
  environment;
11
12
  constructor(clientOptions, stelliaOptions) {
12
13
  super(clientOptions);
14
+ if (stelliaOptions?.environment) {
15
+ this.environment = stelliaOptions.environment;
16
+ }
13
17
  if (stelliaOptions?.managers.autoCompletes?.directoryPath) {
14
18
  this.managers.autoCompletes = new AutoCompleteManager(this, stelliaOptions.managers.autoCompletes.directoryPath);
15
19
  }
@@ -31,29 +35,26 @@ export class StelliaClient extends Client {
31
35
  if (stelliaOptions?.managers.modals?.directoryPath) {
32
36
  this.managers.modals = new ModalManager(this, stelliaOptions.managers.modals.directoryPath);
33
37
  }
34
- if (stelliaOptions?.environment) {
35
- this.environment = stelliaOptions.environment;
36
- }
37
38
  this.utils = new StelliaUtils(this);
38
39
  process.on("unhandledRejection", (error) => {
39
- console.error(`Unhandled promise rejection: ${error}`);
40
+ logger.error(`Unhandled promise rejection: ${error}`);
40
41
  });
41
42
  }
42
43
  connect = async (token) => {
43
44
  if (!this.areManagersLoaded()) {
44
45
  setTimeout(() => {
45
- console.log("Managers are not loaded yet, retrying in 500ms...");
46
+ logger.warn("Managers are not loaded yet, retrying in 500ms...");
46
47
  this.connect(token);
47
48
  }, 500);
48
49
  return;
49
50
  }
50
- console.log("Managers are loaded, connecting to Discord...");
51
+ logger.success("Managers are loaded, connecting to Discord...");
51
52
  await this.login(token);
52
53
  };
53
54
  initializeCommands = async () => {
54
55
  await this.utils.initializeCommands();
55
56
  };
56
- getEnvironment = async () => {
57
+ getGuildsConfiguration = async () => {
57
58
  const chosenEnvironment = process.argv.find(arg => arg.startsWith("--config"))?.split("=")[1];
58
59
  if (!chosenEnvironment) {
59
60
  throw new Error("Environment not provided");
@@ -82,6 +83,9 @@ export class StelliaClient extends Client {
82
83
  });
83
84
  });
84
85
  };
86
+ getGuildConfiguration = (guildId) => {
87
+ return this.utils.getGuildConfiguration(guildId);
88
+ };
85
89
  handleInteraction = async (interaction) => {
86
90
  await this.utils.handleInteraction(interaction);
87
91
  };
@@ -1,11 +1,13 @@
1
1
  import { type StelliaClient } from "./index.js";
2
2
  import { type Interaction } from "discord.js";
3
+ import { type GuildConfiguration } from "../typescript/index.js";
3
4
  export declare class StelliaUtils {
4
5
  readonly client: StelliaClient;
5
6
  private readonly interactionHandlers;
6
- private environment;
7
+ private guildsConfiguration;
7
8
  constructor(client: StelliaClient);
8
9
  initializeCommands: () => Promise<void>;
10
+ getGuildConfiguration: (guildId: string) => GuildConfiguration | undefined;
9
11
  handleInteraction: (interaction: Interaction<"cached">) => Promise<void>;
10
12
  private handleAutoCompleteInteraction;
11
13
  private handleButtonInteraction;
@@ -1,10 +1,11 @@
1
1
  import { ApplicationCommandType, REST, Routes } from "discord.js";
2
2
  import { DISCORD_API_VERSION } from "../constants/index.js";
3
3
  import { InteractionType } from "../typescript/index.js";
4
+ import { logger } from "../utils/logger.js";
4
5
  export class StelliaUtils {
5
6
  client;
6
7
  interactionHandlers;
7
- environment;
8
+ guildsConfiguration;
8
9
  constructor(client) {
9
10
  this.client = client;
10
11
  this.interactionHandlers = new Map([
@@ -15,13 +16,13 @@ export class StelliaUtils {
15
16
  [InteractionType.ModalSubmit, this.handleModalInteraction],
16
17
  [InteractionType.SelectMenu, this.handleSelectMenuInteraction]
17
18
  ]);
18
- if (this.client.environment.areEnvironmentsEnabled) {
19
- this.client.getEnvironment()
20
- .then((environment) => {
21
- this.environment = environment;
22
- console.log("Environment loaded");
19
+ if (this.client.environment.areGuildsConfigurationEnabled) {
20
+ this.client.getGuildsConfiguration()
21
+ .then((guildsConfiguration) => {
22
+ this.guildsConfiguration = guildsConfiguration;
23
+ logger.success("Guilds configuration loaded successfully for interactions");
23
24
  })
24
- .catch((error) => console.error(error));
25
+ .catch((error) => logger.error(`Error while loading guilds configuration: ${error}`));
25
26
  }
26
27
  }
27
28
  initializeCommands = async () => {
@@ -32,12 +33,24 @@ export class StelliaUtils {
32
33
  const rest = new REST({ version: DISCORD_API_VERSION }).setToken(this.client.token);
33
34
  try {
34
35
  await rest.put(Routes.applicationCommands(this.client.user.id), { body: applicationCommands });
36
+ logger.success("Application commands registered successfully");
35
37
  }
36
38
  catch (error) {
37
- console.error(error);
39
+ logger.error(`Error while registering application commands: ${error}`);
38
40
  }
39
41
  }
40
42
  };
43
+ getGuildConfiguration = (guildId) => {
44
+ if (!this.client.environment.areGuildsConfigurationEnabled || !this.guildsConfiguration) {
45
+ return undefined;
46
+ }
47
+ const { guilds, general } = this.guildsConfiguration;
48
+ const guildConfiguration = guilds[guildId];
49
+ return {
50
+ general: general,
51
+ guild: guildConfiguration
52
+ };
53
+ };
41
54
  handleInteraction = async (interaction) => {
42
55
  if (interaction.inCachedGuild()) {
43
56
  const interactionType = this.getInteractionType(interaction);
@@ -59,17 +72,18 @@ export class StelliaUtils {
59
72
  const autoComplete = autoCompleteManager.getByCustomId(autoCompleteInteraction.commandName);
60
73
  if (!autoComplete)
61
74
  return;
62
- if (this.client.environment.areEnvironmentsEnabled) {
63
- const autoCompleteWithEnv = autoComplete;
64
- await autoCompleteWithEnv.execute(this.client, this.environment, autoCompleteInteraction);
75
+ if (this.client.environment.areGuildsConfigurationEnabled) {
76
+ const autoCompleteWithGuildConfiguration = autoComplete;
77
+ const guildConfiguration = this.getGuildConfiguration(autoCompleteInteraction.guildId);
78
+ await autoCompleteWithGuildConfiguration.execute(this.client, guildConfiguration, autoCompleteInteraction);
65
79
  }
66
80
  else {
67
- const autoCompleteWithoutEnv = autoComplete;
68
- await autoCompleteWithoutEnv.execute(this.client, autoCompleteInteraction);
81
+ const autoCompleteWithoutGuildConfiguration = autoComplete;
82
+ await autoCompleteWithoutGuildConfiguration.execute(this.client, autoCompleteInteraction);
69
83
  }
70
84
  }
71
85
  catch (error) {
72
- console.error(error);
86
+ logger.error(`Error while handling autocomplete interaction: ${error}`);
73
87
  }
74
88
  };
75
89
  handleButtonInteraction = async (interaction) => {
@@ -81,17 +95,18 @@ export class StelliaUtils {
81
95
  const button = buttonManager.getByCustomId(buttonInteraction.customId) || buttonManager.getByRegex(buttonInteraction.customId);
82
96
  if (!button)
83
97
  return;
84
- if (this.client.environment.areEnvironmentsEnabled) {
85
- const buttonWithEnv = button;
86
- await buttonWithEnv.execute(this.client, this.environment, buttonInteraction);
98
+ if (this.client.environment.areGuildsConfigurationEnabled) {
99
+ const buttonWithGuildConfiguration = button;
100
+ const guildConfiguration = this.getGuildConfiguration(buttonInteraction.guildId);
101
+ await buttonWithGuildConfiguration.execute(this.client, guildConfiguration, buttonInteraction);
87
102
  }
88
103
  else {
89
- const buttonWithoutEnv = button;
90
- await buttonWithoutEnv.execute(this.client, buttonInteraction);
104
+ const buttonWithoutGuildConfiguration = button;
105
+ await buttonWithoutGuildConfiguration.execute(this.client, buttonInteraction);
91
106
  }
92
107
  }
93
108
  catch (error) {
94
- console.error(error);
109
+ logger.error(`Error while handling button interaction: ${error}`);
95
110
  }
96
111
  };
97
112
  handleCommandInteraction = async (interaction) => {
@@ -103,17 +118,18 @@ export class StelliaUtils {
103
118
  let command = commandManager.getByCustomId(commandInteraction.commandName);
104
119
  if (!command)
105
120
  return;
106
- if (this.client.environment.areEnvironmentsEnabled) {
107
- const commandWithEnv = command;
108
- await commandWithEnv.execute(this.client, this.environment, commandInteraction);
121
+ if (this.client.environment.areGuildsConfigurationEnabled) {
122
+ const commandWithGuildConfiguration = command;
123
+ const guildConfiguration = this.getGuildConfiguration(commandInteraction.guildId);
124
+ await commandWithGuildConfiguration.execute(this.client, guildConfiguration, commandInteraction);
109
125
  }
110
126
  else {
111
- const commandWithoutEnv = command;
112
- await commandWithoutEnv.execute(this.client, commandInteraction);
127
+ const commandWithoutGuildConfiguration = command;
128
+ await commandWithoutGuildConfiguration.execute(this.client, commandInteraction);
113
129
  }
114
130
  }
115
131
  catch (error) {
116
- console.error(error);
132
+ logger.error(`Error while handling command interaction: ${error}`);
117
133
  }
118
134
  };
119
135
  handleContextMenuInteraction = async (interaction) => {
@@ -129,7 +145,7 @@ export class StelliaUtils {
129
145
  }
130
146
  }
131
147
  catch (error) {
132
- console.error(error);
148
+ logger.error(`Error while handling context menu interaction: ${error}`);
133
149
  }
134
150
  };
135
151
  handleModalInteraction = async (interaction) => {
@@ -141,17 +157,18 @@ export class StelliaUtils {
141
157
  const modal = modalManager.getByCustomId(modalInteraction.customId) || modalManager.getByRegex(modalInteraction.customId);
142
158
  if (!modal)
143
159
  return;
144
- if (this.client.environment.areEnvironmentsEnabled) {
145
- const modalWithEnv = modal;
146
- await modalWithEnv.execute(this.client, this.environment, modalInteraction);
160
+ if (this.client.environment.areGuildsConfigurationEnabled) {
161
+ const modalWithGuildConfiguration = modal;
162
+ const guildConfiguration = this.getGuildConfiguration(modalInteraction.guildId);
163
+ await modalWithGuildConfiguration.execute(this.client, guildConfiguration, modalInteraction);
147
164
  }
148
165
  else {
149
- const modalWithoutEnv = modal;
150
- await modalWithoutEnv.execute(this.client, modalInteraction);
166
+ const modalWithoutGuildConfiguration = modal;
167
+ await modalWithoutGuildConfiguration.execute(this.client, modalInteraction);
151
168
  }
152
169
  }
153
170
  catch (error) {
154
- console.error(error);
171
+ logger.error(`Error while handling modal interaction: ${error}`);
155
172
  }
156
173
  };
157
174
  handleSelectMenuInteraction = async (interaction) => {
@@ -163,17 +180,18 @@ export class StelliaUtils {
163
180
  const selectMenu = selectMenuManager.getByCustomId(selectMenuInteraction.customId) || selectMenuManager.getByRegex(selectMenuInteraction.customId);
164
181
  if (!selectMenu)
165
182
  return;
166
- if (this.client.environment.areEnvironmentsEnabled) {
167
- const selectMenuWithEnv = selectMenu;
168
- await selectMenuWithEnv.execute(this.client, this.environment, selectMenuInteraction);
183
+ if (this.client.environment.areGuildsConfigurationEnabled) {
184
+ const selectMenuWithGuildConfiguration = selectMenu;
185
+ const guildConfiguration = this.getGuildConfiguration(selectMenuInteraction.guildId);
186
+ await selectMenuWithGuildConfiguration.execute(this.client, guildConfiguration, selectMenuInteraction);
169
187
  }
170
188
  else {
171
- const modalWithoutEnv = selectMenu;
172
- await modalWithoutEnv.execute(this.client, selectMenuInteraction);
189
+ const modalWithoutGuildConfiguration = selectMenu;
190
+ await modalWithoutGuildConfiguration.execute(this.client, selectMenuInteraction);
173
191
  }
174
192
  }
175
193
  catch (error) {
176
- console.error(error);
194
+ logger.error(`Error while handling select menu interaction: ${error}`);
177
195
  }
178
196
  };
179
197
  handleMessageContextMenuInteraction = async (interaction) => {
@@ -184,17 +202,18 @@ export class StelliaUtils {
184
202
  const messageContextMenu = contextMenuManager.getByCustomId(interaction.commandName);
185
203
  if (!messageContextMenu)
186
204
  return;
187
- if (this.client.environment.areEnvironmentsEnabled) {
188
- const messageContextMenuWithEnv = messageContextMenu;
189
- await messageContextMenuWithEnv.execute(this.client, this.environment, interaction);
205
+ if (this.client.environment.areGuildsConfigurationEnabled) {
206
+ const messageContextMenuWithGuildConfiguration = messageContextMenu;
207
+ const guildConfiguration = this.getGuildConfiguration(interaction.guildId);
208
+ await messageContextMenuWithGuildConfiguration.execute(this.client, guildConfiguration, interaction);
190
209
  }
191
210
  else {
192
- const messageContextMenuWithoutEnv = messageContextMenu;
193
- await messageContextMenuWithoutEnv.execute(this.client, interaction);
211
+ const messageContextMenuWithoutGuildConfiguration = messageContextMenu;
212
+ await messageContextMenuWithoutGuildConfiguration.execute(this.client, interaction);
194
213
  }
195
214
  }
196
215
  catch (error) {
197
- console.error(error);
216
+ logger.error(`Error while handling message context menu interaction: ${error}`);
198
217
  }
199
218
  };
200
219
  handleUserContextMenuInteraction = async (interaction) => {
@@ -205,17 +224,18 @@ export class StelliaUtils {
205
224
  const userContextMenu = contextMenuManager.getByCustomId(interaction.commandName);
206
225
  if (!userContextMenu)
207
226
  return;
208
- if (this.client.environment.areEnvironmentsEnabled) {
209
- const userContextMenuWithEnv = userContextMenu;
210
- await userContextMenuWithEnv.execute(this.client, this.environment, interaction);
227
+ if (this.client.environment.areGuildsConfigurationEnabled) {
228
+ const userContextMenuWithGuildConfiguration = userContextMenu;
229
+ const guildConfiguration = this.getGuildConfiguration(interaction.guildId);
230
+ await userContextMenuWithGuildConfiguration.execute(this.client, guildConfiguration, interaction);
211
231
  }
212
232
  else {
213
- const userContextMenuWithoutEnv = userContextMenu;
214
- await userContextMenuWithoutEnv.execute(this.client, interaction);
233
+ const userContextMenuWithoutGuildConfiguration = userContextMenu;
234
+ await userContextMenuWithoutGuildConfiguration.execute(this.client, interaction);
215
235
  }
216
236
  }
217
237
  catch (error) {
218
- console.error(error);
238
+ logger.error(`Error while handling user context menu interaction: ${error}`);
219
239
  }
220
240
  };
221
241
  getInteractionType(interaction) {
@@ -4,9 +4,14 @@ import { BaseManager } from "./index.js";
4
4
  import { type StructureCustomId, type InteractionCustomId } from "../typescript/index.js";
5
5
  export declare class EventManager extends BaseManager {
6
6
  private interactions;
7
+ private guildsConfiguration;
7
8
  constructor(client: StelliaClient, directoryPath: string);
8
9
  loadData(): Promise<void>;
9
10
  getByCustomId<EventStructure>(id: InteractionCustomId): EventStructure | undefined;
10
11
  getByRegex<EventStructure>(id: InteractionCustomId): EventStructure | undefined;
11
12
  getAll<EventStructure>(): Collection<StructureCustomId, EventStructure>;
13
+ private loadEventWithGuildConfiguration;
14
+ private eventHandler;
15
+ private loadEventWithoutGuildConfiguration;
16
+ private getGuildConfiguration;
12
17
  }
@@ -1,45 +1,32 @@
1
- import { Collection, Events } from "discord.js";
1
+ import { Collection } from "discord.js";
2
2
  import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
+ import { logger } from "../utils/logger.js";
4
5
  export class EventManager extends BaseManager {
5
6
  interactions = new Collection();
7
+ guildsConfiguration;
6
8
  constructor(client, directoryPath) {
7
9
  super(client, directoryPath);
10
+ if (this.client.environment.areGuildsConfigurationEnabled) {
11
+ this.client.getGuildsConfiguration()
12
+ .then((guildsConfiguration) => {
13
+ this.guildsConfiguration = guildsConfiguration;
14
+ logger.success("Guilds configuration loaded successfully for event manager");
15
+ })
16
+ .catch((error) => logger.error(`Error while loading guilds configuration: ${error}`));
17
+ }
8
18
  }
9
19
  async loadData() {
10
20
  const events = await requiredFiles(this.directoryPath);
11
21
  this.interactions = events;
12
22
  for (const eventStructure of this.interactions.values()) {
13
- const { name, once } = eventStructure.data;
14
- if (this.client.environment.areEnvironmentsEnabled) {
15
- const environment = await this.client.getEnvironment();
16
- const event = eventStructure;
17
- if (name == Events.ClientReady) {
18
- this.client.once(Events.ClientReady, () => event.execute(this.client, environment));
19
- continue;
20
- }
21
- if (once) {
22
- this.client.once(name, (...args) => event.execute(this.client, environment, ...args));
23
- }
24
- else {
25
- this.client.on(name, (...args) => event.execute(this.client, environment, ...args));
26
- }
23
+ if (this.client.environment.areGuildsConfigurationEnabled) {
24
+ await this.loadEventWithGuildConfiguration(eventStructure);
27
25
  }
28
26
  else {
29
- const event = eventStructure;
30
- if (name == Events.ClientReady) {
31
- this.client.once(name, () => event.execute(this.client));
32
- continue;
33
- }
34
- if (once) {
35
- this.client.once(name, (...args) => event.execute(this.client, ...args));
36
- }
37
- else {
38
- this.client.on(name, (...args) => event.execute(this.client, ...args));
39
- }
27
+ await this.loadEventWithoutGuildConfiguration(eventStructure);
40
28
  }
41
29
  }
42
- this.client.on(Events.Error, (error) => console.error(error));
43
30
  this.setManagerLoaded();
44
31
  }
45
32
  getByCustomId(id) {
@@ -53,4 +40,45 @@ export class EventManager extends BaseManager {
53
40
  const events = this.interactions;
54
41
  return events;
55
42
  }
43
+ async loadEventWithGuildConfiguration(eventStructure) {
44
+ const { name, once } = eventStructure.data;
45
+ const event = eventStructure;
46
+ if (once) {
47
+ this.client.once(name, (...args) => this.eventHandler(event, ...args));
48
+ }
49
+ else {
50
+ this.client.on(name, (...args) => this.eventHandler(event, ...args));
51
+ }
52
+ }
53
+ eventHandler = (event, ...args) => {
54
+ const mainArgument = args[0];
55
+ const guildConfiguration = this.getGuildConfiguration(mainArgument);
56
+ if (guildConfiguration) {
57
+ const eventStructure = event;
58
+ return eventStructure.execute(this.client, guildConfiguration, ...args);
59
+ }
60
+ const eventStructure = event;
61
+ return eventStructure.execute(this.client, this.guildsConfiguration);
62
+ };
63
+ async loadEventWithoutGuildConfiguration(eventStructure) {
64
+ const { name, once } = eventStructure.data;
65
+ const event = eventStructure;
66
+ if (once) {
67
+ this.client.once(name, (...args) => event.execute(this.client, ...args));
68
+ }
69
+ else {
70
+ this.client.on(name, (...args) => event.execute(this.client, ...args));
71
+ }
72
+ }
73
+ getGuildConfiguration(mainArgument) {
74
+ if (mainArgument && typeof mainArgument === "object") {
75
+ if ("guildId" in mainArgument && mainArgument.guildId) {
76
+ return this.client.getGuildConfiguration(mainArgument.guildId);
77
+ }
78
+ if ("guild" in mainArgument && mainArgument.guild) {
79
+ return this.client.getGuildConfiguration(mainArgument.guild.id);
80
+ }
81
+ }
82
+ return undefined;
83
+ }
56
84
  }
@@ -1,19 +1,24 @@
1
1
  import { type Awaitable, type ClientEvents } from "discord.js";
2
2
  import { type StelliaClient } from "../client/index.js";
3
- import { type EnvironmentConfiguration } from "../typescript/types.js";
4
- export interface EventStructureWithEnvironment extends EventInteractionStructure {
5
- execute(client: StelliaClient, environment: EnvironmentConfiguration, ...args: ClientEvents[Event]): Awaitable<unknown>;
3
+ import { type GuildConfigurationType, type GuildsConfiguration } from "../typescript/types.js";
4
+ export interface EventStructureWithGuildConfiguration extends EventInteractionStructure {
5
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, ...args: ClientEventsArgs): Awaitable<unknown>;
6
6
  }
7
- export interface EventStructureWithoutEnvironment extends EventInteractionStructure {
8
- execute(client: StelliaClient, ...args: ClientEvents[Event]): Awaitable<unknown>;
7
+ export interface EventStructureWithAllGuildsConfiguration extends EventInteractionStructure {
8
+ execute(client: StelliaClient, guildsConfiguration: GuildsConfiguration, ...args: ClientEventsArgs): Awaitable<unknown>;
9
9
  }
10
- export type EventStructure = EventStructureWithEnvironment | EventStructureWithoutEnvironment;
10
+ export interface EventStructureWithoutGuildConfiguration extends EventInteractionStructure {
11
+ execute(client: StelliaClient, ...args: ClientEventsArgs): Awaitable<unknown>;
12
+ }
13
+ export type EventStructureWithConfiguration = EventStructureWithGuildConfiguration | EventStructureWithAllGuildsConfiguration;
14
+ export type EventStructure = EventStructureWithGuildConfiguration | EventStructureWithAllGuildsConfiguration | EventStructureWithoutGuildConfiguration;
11
15
  interface EventInteractionStructure {
12
16
  data: EventDataStructure;
13
17
  }
14
18
  interface EventDataStructure {
15
- name: Event;
19
+ name: EventKeys;
16
20
  once: boolean;
17
21
  }
18
- type Event = keyof ClientEvents;
22
+ export type ClientEventsArgs = ClientEvents[keyof ClientEvents];
23
+ export type EventKeys = keyof ClientEvents;
19
24
  export {};
@@ -1,49 +1,49 @@
1
1
  import { type AnySelectMenuInteraction, type AutocompleteInteraction, type Awaitable, type ButtonInteraction, type ChatInputCommandInteraction, type ContextMenuCommandType, type MessageContextMenuCommandInteraction, type ModalSubmitInteraction, type SlashCommandOptionsOnlyBuilder, type UserContextMenuCommandInteraction } from "discord.js";
2
2
  import { type StelliaClient } from "../client/index.js";
3
- import { type EnvironmentConfiguration } from "../typescript/index.js";
3
+ import { type GuildConfigurationType } from "../typescript/index.js";
4
4
  import { type EventStructure } from "./Event.js";
5
- export interface AutoCompleteStructureWithEnvironment extends MessageInteractionStructure {
6
- execute(client: StelliaClient, environment: EnvironmentConfiguration, interaction: AutocompleteInteraction<"cached">): Awaitable<unknown>;
5
+ export interface AutoCompleteStructureWithGuildConfiguration extends MessageInteractionStructure {
6
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, interaction: AutocompleteInteraction<"cached">): Awaitable<unknown>;
7
7
  }
8
- export interface AutoCompleteStructureWithoutEnvironment extends MessageInteractionStructure {
8
+ export interface AutoCompleteStructureWithoutGuildConfiguration extends MessageInteractionStructure {
9
9
  execute(client: StelliaClient, interaction: AutocompleteInteraction<"cached">): Awaitable<unknown>;
10
10
  }
11
- export type AutoCompleteStructure = AutoCompleteStructureWithEnvironment | AutoCompleteStructureWithoutEnvironment;
12
- export interface ButtonStructureWithEnvironment extends MessageInteractionStructure {
13
- execute(client: StelliaClient, environment: EnvironmentConfiguration, interaction: ButtonInteraction<"cached">): Awaitable<unknown>;
11
+ export type AutoCompleteStructure = AutoCompleteStructureWithGuildConfiguration | AutoCompleteStructureWithoutGuildConfiguration;
12
+ export interface ButtonStructureWithGuildConfiguration extends MessageInteractionStructure {
13
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, interaction: ButtonInteraction<"cached">): Awaitable<unknown>;
14
14
  }
15
- export interface ButtonStructureWithoutEnvironment extends MessageInteractionStructure {
15
+ export interface ButtonStructureWithoutGuildConfiguration extends MessageInteractionStructure {
16
16
  execute(client: StelliaClient, interaction: ButtonInteraction<"cached">): Awaitable<unknown>;
17
17
  }
18
- export type ButtonStructure = ButtonStructureWithEnvironment | ButtonStructureWithoutEnvironment;
19
- export interface CommandStructureWithEnvironment extends CommandInteractionStructure {
20
- execute(client: StelliaClient, environment: EnvironmentConfiguration, interaction: ChatInputCommandInteraction<"cached">): Awaitable<unknown>;
18
+ export type ButtonStructure = ButtonStructureWithGuildConfiguration | ButtonStructureWithoutGuildConfiguration;
19
+ export interface CommandStructureWithGuildConfiguration extends CommandInteractionStructure {
20
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, interaction: ChatInputCommandInteraction<"cached">): Awaitable<unknown>;
21
21
  }
22
- export interface CommandStructureWithoutEnvironment extends CommandInteractionStructure {
22
+ export interface CommandStructureWithoutGuildConfiguration extends CommandInteractionStructure {
23
23
  execute(client: StelliaClient, interaction: ChatInputCommandInteraction<"cached">): Awaitable<unknown>;
24
24
  }
25
- export type CommandStructure = CommandStructureWithEnvironment | CommandStructureWithoutEnvironment;
26
- export interface ContextMenuStructureWithEnvironment extends ContextMenuInteractionStructure {
27
- execute(client: StelliaClient, environment: EnvironmentConfiguration, interaction: MessageContextMenuCommandInteraction<"cached"> | UserContextMenuCommandInteraction<"cached">): Awaitable<unknown>;
25
+ export type CommandStructure = CommandStructureWithGuildConfiguration | CommandStructureWithoutGuildConfiguration;
26
+ export interface ContextMenuStructureWithGuildConfiguration extends ContextMenuInteractionStructure {
27
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, interaction: MessageContextMenuCommandInteraction<"cached"> | UserContextMenuCommandInteraction<"cached">): Awaitable<unknown>;
28
28
  }
29
- export interface ContextMenuStructureWithoutEnvironment extends ContextMenuInteractionStructure {
29
+ export interface ContextMenuStructureWithoutGuildConfiguration extends ContextMenuInteractionStructure {
30
30
  execute(client: StelliaClient, interaction: MessageContextMenuCommandInteraction<"cached"> | UserContextMenuCommandInteraction<"cached">): Awaitable<unknown>;
31
31
  }
32
- export type ContextMenuStructure = ContextMenuStructureWithEnvironment | ContextMenuStructureWithoutEnvironment;
33
- export interface ModalStructureWithEnvironment extends MessageInteractionStructure {
34
- execute(client: StelliaClient, environment: EnvironmentConfiguration, interaction: ModalSubmitInteraction<"cached">): Awaitable<unknown>;
32
+ export type ContextMenuStructure = ContextMenuStructureWithGuildConfiguration | ContextMenuStructureWithoutGuildConfiguration;
33
+ export interface ModalStructureWithGuildConfiguration extends MessageInteractionStructure {
34
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, interaction: ModalSubmitInteraction<"cached">): Awaitable<unknown>;
35
35
  }
36
- export interface ModalStructureWithoutEnvironment extends MessageInteractionStructure {
36
+ export interface ModalStructureWithoutGuildConfiguration extends MessageInteractionStructure {
37
37
  execute(client: StelliaClient, interaction: ModalSubmitInteraction<"cached">): Awaitable<unknown>;
38
38
  }
39
- export type ModalStructure = ModalStructureWithEnvironment | ModalStructureWithoutEnvironment;
40
- export interface SelectMenuStructureWithEnvironment extends MessageInteractionStructure {
41
- execute(client: StelliaClient, environment: EnvironmentConfiguration, interaction: AnySelectMenuInteraction<"cached">): Awaitable<unknown>;
39
+ export type ModalStructure = ModalStructureWithGuildConfiguration | ModalStructureWithoutGuildConfiguration;
40
+ export interface SelectMenuStructureWithGuildConfiguration extends MessageInteractionStructure {
41
+ execute(client: StelliaClient, guildConfiguration: GuildConfigurationType, interaction: AnySelectMenuInteraction<"cached">): Awaitable<unknown>;
42
42
  }
43
- export interface SelectMenuStructureWithoutEnvironment extends MessageInteractionStructure {
43
+ export interface SelectMenuStructureWithoutGuildConfiguration extends MessageInteractionStructure {
44
44
  execute(client: StelliaClient, interaction: AnySelectMenuInteraction<"cached">): Awaitable<unknown>;
45
45
  }
46
- export type SelectMenuStructure = SelectMenuStructureWithEnvironment | SelectMenuStructureWithoutEnvironment;
46
+ export type SelectMenuStructure = SelectMenuStructureWithGuildConfiguration | SelectMenuStructureWithoutGuildConfiguration;
47
47
  export type AnyInteractionStructure = AutoCompleteStructure | ButtonStructure | CommandStructure | ContextMenuStructure | EventStructure | ModalStructure | SelectMenuStructure;
48
48
  interface CommandInteractionStructure {
49
49
  data: SlashCommandOptionsOnlyBuilder;
@@ -1,4 +1,5 @@
1
1
  import { type AutoCompleteManager, type ButtonManager, type CommandManager, type ContextMenuManager, type EventManager, type ModalManager, type SelectMenuManager } from "../managers/index.js";
2
+ import { type Snowflake } from "discord.js";
2
3
  export type StructureCustomId = string | RegExp;
3
4
  export type InteractionCustomId = string;
4
5
  export declare enum InteractionType {
@@ -20,9 +21,26 @@ export interface Managers {
20
21
  selectMenus?: SelectMenuManager;
21
22
  modals?: ModalManager;
22
23
  }
23
- export interface Environment {
24
- areEnvironmentsEnabled: boolean;
24
+ export interface ClientEnvironment {
25
+ areGuildsConfigurationEnabled: boolean;
25
26
  }
26
- export interface EnvironmentConfiguration {
27
+ export interface BaseGuildConfiguration {
28
+ locale: string;
27
29
  [key: string]: unknown;
28
30
  }
31
+ export interface BaseGeneralConfiguration {
32
+ [key: string]: unknown;
33
+ }
34
+ export interface GuildsConfiguration {
35
+ general: {
36
+ [key: string]: unknown;
37
+ };
38
+ guilds: {
39
+ [guildId in Snowflake]: BaseGuildConfiguration;
40
+ };
41
+ }
42
+ export interface GuildConfiguration {
43
+ general: BaseGeneralConfiguration;
44
+ guild: BaseGuildConfiguration;
45
+ }
46
+ export type GuildConfigurationType = GuildConfiguration | undefined;
@@ -1,2 +1,3 @@
1
1
  export * from "./ephemeralReponse.js";
2
2
  export * from "./files.js";
3
+ export * from "./logger.js";
@@ -1,2 +1,3 @@
1
1
  export * from "./ephemeralReponse.js";
2
2
  export * from "./files.js";
3
+ export * from "./logger.js";
@@ -0,0 +1,6 @@
1
+ export declare const logger: {
2
+ info: (message: string) => void;
3
+ success: (message: string) => void;
4
+ warn: (message: string) => void;
5
+ error: (message: string) => void;
6
+ };
@@ -0,0 +1,15 @@
1
+ import logSymbols from "log-symbols";
2
+ export const logger = {
3
+ info: (message) => {
4
+ console.log(`${logSymbols.info} ${message}`);
5
+ },
6
+ success: (message) => {
7
+ console.log(`${logSymbols.success} ${message}`);
8
+ },
9
+ warn: (message) => {
10
+ console.warn(`${logSymbols.warning} ${message}`);
11
+ },
12
+ error: (message) => {
13
+ console.error(`${logSymbols.error} ${message}`);
14
+ }
15
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stelliajs/framework",
3
- "version": "1.3.0-dev-1",
3
+ "version": "1.3.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "scripts": {
@@ -15,13 +15,14 @@
15
15
  "description": "A framework for simplify the creation of discord bots",
16
16
  "keywords": ["discord", "bot", "discordjs", "typescript", "framework"],
17
17
  "dependencies": {
18
- "discord-api-types": "^0.38.2",
19
- "discord.js": "^14.19.3"
18
+ "discord-api-types": "^0.38.10",
19
+ "discord.js": "^14.19.3",
20
+ "log-symbols": "^7.0.1"
20
21
  },
21
22
  "devDependencies": {
22
23
  "ts-node": "^10.9.2",
23
- "tsc-alias": "^1.8.15"
24
+ "tsc-alias": "^1.8.16"
24
25
  },
25
26
  "type": "module",
26
- "packageManager": "pnpm@10.10.0"
27
+ "packageManager": "pnpm@10.11.1"
27
28
  }