@stelliajs/framework 1.3.0-dev-1 → 1.3.0-dev-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
@@ -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,6 +4,7 @@ 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 = {};
@@ -36,24 +37,24 @@ export class StelliaClient extends Client {
36
37
  }
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,21 @@ 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 { general, guild: guildConfiguration };
50
+ };
41
51
  handleInteraction = async (interaction) => {
42
52
  if (interaction.inCachedGuild()) {
43
53
  const interactionType = this.getInteractionType(interaction);
@@ -59,17 +69,18 @@ export class StelliaUtils {
59
69
  const autoComplete = autoCompleteManager.getByCustomId(autoCompleteInteraction.commandName);
60
70
  if (!autoComplete)
61
71
  return;
62
- if (this.client.environment.areEnvironmentsEnabled) {
63
- const autoCompleteWithEnv = autoComplete;
64
- await autoCompleteWithEnv.execute(this.client, this.environment, autoCompleteInteraction);
72
+ if (this.client.environment.areGuildsConfigurationEnabled) {
73
+ const autoCompleteWithGuildConfiguration = autoComplete;
74
+ const guildConfiguration = this.getGuildConfiguration(autoCompleteInteraction.guildId);
75
+ await autoCompleteWithGuildConfiguration.execute(this.client, guildConfiguration, autoCompleteInteraction);
65
76
  }
66
77
  else {
67
- const autoCompleteWithoutEnv = autoComplete;
68
- await autoCompleteWithoutEnv.execute(this.client, autoCompleteInteraction);
78
+ const autoCompleteWithoutGuildConfiguration = autoComplete;
79
+ await autoCompleteWithoutGuildConfiguration.execute(this.client, autoCompleteInteraction);
69
80
  }
70
81
  }
71
82
  catch (error) {
72
- console.error(error);
83
+ logger.error(`Error while handling autocomplete interaction: ${error}`);
73
84
  }
74
85
  };
75
86
  handleButtonInteraction = async (interaction) => {
@@ -81,17 +92,18 @@ export class StelliaUtils {
81
92
  const button = buttonManager.getByCustomId(buttonInteraction.customId) || buttonManager.getByRegex(buttonInteraction.customId);
82
93
  if (!button)
83
94
  return;
84
- if (this.client.environment.areEnvironmentsEnabled) {
85
- const buttonWithEnv = button;
86
- await buttonWithEnv.execute(this.client, this.environment, buttonInteraction);
95
+ if (this.client.environment.areGuildsConfigurationEnabled) {
96
+ const buttonWithGuildConfiguration = button;
97
+ const guildConfiguration = this.getGuildConfiguration(buttonInteraction.guildId);
98
+ await buttonWithGuildConfiguration.execute(this.client, guildConfiguration, buttonInteraction);
87
99
  }
88
100
  else {
89
- const buttonWithoutEnv = button;
90
- await buttonWithoutEnv.execute(this.client, buttonInteraction);
101
+ const buttonWithoutGuildConfiguration = button;
102
+ await buttonWithoutGuildConfiguration.execute(this.client, buttonInteraction);
91
103
  }
92
104
  }
93
105
  catch (error) {
94
- console.error(error);
106
+ logger.error(`Error while handling button interaction: ${error}`);
95
107
  }
96
108
  };
97
109
  handleCommandInteraction = async (interaction) => {
@@ -103,17 +115,18 @@ export class StelliaUtils {
103
115
  let command = commandManager.getByCustomId(commandInteraction.commandName);
104
116
  if (!command)
105
117
  return;
106
- if (this.client.environment.areEnvironmentsEnabled) {
107
- const commandWithEnv = command;
108
- await commandWithEnv.execute(this.client, this.environment, commandInteraction);
118
+ if (this.client.environment.areGuildsConfigurationEnabled) {
119
+ const commandWithGuildConfiguration = command;
120
+ const guildConfiguration = this.getGuildConfiguration(commandInteraction.guildId);
121
+ await commandWithGuildConfiguration.execute(this.client, guildConfiguration, commandInteraction);
109
122
  }
110
123
  else {
111
- const commandWithoutEnv = command;
112
- await commandWithoutEnv.execute(this.client, commandInteraction);
124
+ const commandWithoutGuildConfiguration = command;
125
+ await commandWithoutGuildConfiguration.execute(this.client, commandInteraction);
113
126
  }
114
127
  }
115
128
  catch (error) {
116
- console.error(error);
129
+ logger.error(`Error while handling command interaction: ${error}`);
117
130
  }
118
131
  };
119
132
  handleContextMenuInteraction = async (interaction) => {
@@ -129,7 +142,7 @@ export class StelliaUtils {
129
142
  }
130
143
  }
131
144
  catch (error) {
132
- console.error(error);
145
+ logger.error(`Error while handling context menu interaction: ${error}`);
133
146
  }
134
147
  };
135
148
  handleModalInteraction = async (interaction) => {
@@ -141,17 +154,18 @@ export class StelliaUtils {
141
154
  const modal = modalManager.getByCustomId(modalInteraction.customId) || modalManager.getByRegex(modalInteraction.customId);
142
155
  if (!modal)
143
156
  return;
144
- if (this.client.environment.areEnvironmentsEnabled) {
145
- const modalWithEnv = modal;
146
- await modalWithEnv.execute(this.client, this.environment, modalInteraction);
157
+ if (this.client.environment.areGuildsConfigurationEnabled) {
158
+ const modalWithGuildConfiguration = modal;
159
+ const guildConfiguration = this.getGuildConfiguration(modalInteraction.guildId);
160
+ await modalWithGuildConfiguration.execute(this.client, guildConfiguration, modalInteraction);
147
161
  }
148
162
  else {
149
- const modalWithoutEnv = modal;
150
- await modalWithoutEnv.execute(this.client, modalInteraction);
163
+ const modalWithoutGuildConfiguration = modal;
164
+ await modalWithoutGuildConfiguration.execute(this.client, modalInteraction);
151
165
  }
152
166
  }
153
167
  catch (error) {
154
- console.error(error);
168
+ logger.error(`Error while handling modal interaction: ${error}`);
155
169
  }
156
170
  };
157
171
  handleSelectMenuInteraction = async (interaction) => {
@@ -163,17 +177,18 @@ export class StelliaUtils {
163
177
  const selectMenu = selectMenuManager.getByCustomId(selectMenuInteraction.customId) || selectMenuManager.getByRegex(selectMenuInteraction.customId);
164
178
  if (!selectMenu)
165
179
  return;
166
- if (this.client.environment.areEnvironmentsEnabled) {
167
- const selectMenuWithEnv = selectMenu;
168
- await selectMenuWithEnv.execute(this.client, this.environment, selectMenuInteraction);
180
+ if (this.client.environment.areGuildsConfigurationEnabled) {
181
+ const selectMenuWithGuildConfiguration = selectMenu;
182
+ const guildConfiguration = this.getGuildConfiguration(selectMenuInteraction.guildId);
183
+ await selectMenuWithGuildConfiguration.execute(this.client, guildConfiguration, selectMenuInteraction);
169
184
  }
170
185
  else {
171
- const modalWithoutEnv = selectMenu;
172
- await modalWithoutEnv.execute(this.client, selectMenuInteraction);
186
+ const modalWithoutGuildConfiguration = selectMenu;
187
+ await modalWithoutGuildConfiguration.execute(this.client, selectMenuInteraction);
173
188
  }
174
189
  }
175
190
  catch (error) {
176
- console.error(error);
191
+ logger.error(`Error while handling select menu interaction: ${error}`);
177
192
  }
178
193
  };
179
194
  handleMessageContextMenuInteraction = async (interaction) => {
@@ -184,17 +199,18 @@ export class StelliaUtils {
184
199
  const messageContextMenu = contextMenuManager.getByCustomId(interaction.commandName);
185
200
  if (!messageContextMenu)
186
201
  return;
187
- if (this.client.environment.areEnvironmentsEnabled) {
188
- const messageContextMenuWithEnv = messageContextMenu;
189
- await messageContextMenuWithEnv.execute(this.client, this.environment, interaction);
202
+ if (this.client.environment.areGuildsConfigurationEnabled) {
203
+ const messageContextMenuWithGuildConfiguration = messageContextMenu;
204
+ const guildConfiguration = this.getGuildConfiguration(interaction.guildId);
205
+ await messageContextMenuWithGuildConfiguration.execute(this.client, guildConfiguration, interaction);
190
206
  }
191
207
  else {
192
- const messageContextMenuWithoutEnv = messageContextMenu;
193
- await messageContextMenuWithoutEnv.execute(this.client, interaction);
208
+ const messageContextMenuWithoutGuildConfiguration = messageContextMenu;
209
+ await messageContextMenuWithoutGuildConfiguration.execute(this.client, interaction);
194
210
  }
195
211
  }
196
212
  catch (error) {
197
- console.error(error);
213
+ logger.error(`Error while handling message context menu interaction: ${error}`);
198
214
  }
199
215
  };
200
216
  handleUserContextMenuInteraction = async (interaction) => {
@@ -205,17 +221,18 @@ export class StelliaUtils {
205
221
  const userContextMenu = contextMenuManager.getByCustomId(interaction.commandName);
206
222
  if (!userContextMenu)
207
223
  return;
208
- if (this.client.environment.areEnvironmentsEnabled) {
209
- const userContextMenuWithEnv = userContextMenu;
210
- await userContextMenuWithEnv.execute(this.client, this.environment, interaction);
224
+ if (this.client.environment.areGuildsConfigurationEnabled) {
225
+ const userContextMenuWithGuildConfiguration = userContextMenu;
226
+ const guildConfiguration = this.getGuildConfiguration(interaction.guildId);
227
+ await userContextMenuWithGuildConfiguration.execute(this.client, guildConfiguration, interaction);
211
228
  }
212
229
  else {
213
- const userContextMenuWithoutEnv = userContextMenu;
214
- await userContextMenuWithoutEnv.execute(this.client, interaction);
230
+ const userContextMenuWithoutGuildConfiguration = userContextMenu;
231
+ await userContextMenuWithoutGuildConfiguration.execute(this.client, interaction);
215
232
  }
216
233
  }
217
234
  catch (error) {
218
- console.error(error);
235
+ logger.error(`Error while handling user context menu interaction: ${error}`);
219
236
  }
220
237
  };
221
238
  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,33 @@
1
1
  import { Collection, Events } 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));
30
+ this.client.on(Events.Error, (error) => logger.error(`Client error: ${error}`));
43
31
  this.setManagerLoaded();
44
32
  }
45
33
  getByCustomId(id) {
@@ -53,4 +41,48 @@ export class EventManager extends BaseManager {
53
41
  const events = this.interactions;
54
42
  return events;
55
43
  }
44
+ async loadEventWithGuildConfiguration(eventStructure) {
45
+ const { name, once } = eventStructure.data;
46
+ const event = eventStructure;
47
+ if (once) {
48
+ this.client.once(name, (...args) => this.eventHandler(event, ...args));
49
+ }
50
+ else {
51
+ this.client.on(name, (...args) => this.eventHandler(event, ...args));
52
+ }
53
+ }
54
+ eventHandler = (event, ...args) => {
55
+ const mainArgument = args[0];
56
+ if (!mainArgument) {
57
+ const eventStructure = event;
58
+ return eventStructure.execute(this.client, this.guildsConfiguration);
59
+ }
60
+ const guildConfiguration = this.getGuildConfiguration(mainArgument);
61
+ if (guildConfiguration) {
62
+ const eventStructure = event;
63
+ return eventStructure.execute(this.client, guildConfiguration, ...args);
64
+ }
65
+ logger.warn(`No guild configuration found for event ${event.data.name} with main argument ${mainArgument}`);
66
+ };
67
+ async loadEventWithoutGuildConfiguration(eventStructure) {
68
+ const { name, once } = eventStructure.data;
69
+ const event = eventStructure;
70
+ if (once) {
71
+ this.client.once(name, (...args) => event.execute(this.client, ...args));
72
+ }
73
+ else {
74
+ this.client.on(name, (...args) => event.execute(this.client, ...args));
75
+ }
76
+ }
77
+ getGuildConfiguration(mainArgument) {
78
+ if (mainArgument && typeof mainArgument === "object") {
79
+ if ("guildId" in mainArgument && mainArgument.guildId) {
80
+ return this.client.getGuildConfiguration(mainArgument.guildId);
81
+ }
82
+ if ("guild" in mainArgument && mainArgument.guild) {
83
+ return this.client.getGuildConfiguration(mainArgument.guild.id);
84
+ }
85
+ }
86
+ return undefined;
87
+ }
56
88
  }
@@ -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;
@@ -20,9 +20,26 @@ export interface Managers {
20
20
  selectMenus?: SelectMenuManager;
21
21
  modals?: ModalManager;
22
22
  }
23
- export interface Environment {
24
- areEnvironmentsEnabled: boolean;
23
+ export interface ClientEnvironment {
24
+ areGuildsConfigurationEnabled: boolean;
25
25
  }
26
- export interface EnvironmentConfiguration {
26
+ export interface BaseGuildConfiguration {
27
+ locale: string;
27
28
  [key: string]: unknown;
28
29
  }
30
+ export interface BaseGeneralConfiguration {
31
+ [key: string]: unknown;
32
+ }
33
+ export interface GuildsConfiguration {
34
+ general: {
35
+ [key: string]: unknown;
36
+ };
37
+ guilds: {
38
+ [guildId: string]: BaseGuildConfiguration;
39
+ };
40
+ }
41
+ export interface GuildConfiguration {
42
+ general: BaseGeneralConfiguration;
43
+ guild: BaseGuildConfiguration;
44
+ }
45
+ export type GuildConfigurationType = GuildConfiguration | undefined;
@@ -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-dev-2",
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
  }