@stelliajs/framework 1.5.4 → 1.5.7

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
@@ -49,108 +49,149 @@ Recommended architecture for StelliaJS project.
49
49
 
50
50
  ### Simple client with environment
51
51
 
52
- ```js
53
- import { GatewayIntentBits, Partials } from "discord.js";
52
+ #### Client initialization
53
+ ```ts
54
54
  import { StelliaClient } from "@stelliajs/framework";
55
+ import { GatewayIntentBits, Partials } from "discord.js";
56
+
57
+ (async () => {
58
+ const client = new StelliaClient({
59
+ intents: [
60
+ GatewayIntentBits.Guilds,
61
+ GatewayIntentBits.GuildMessages,
62
+ GatewayIntentBits.MessageContent,
63
+ GatewayIntentBits.GuildMembers
64
+ ],
65
+ partials: [Partials.Message, Partials.GuildMember]
66
+ },
67
+ {
68
+ managers: {
69
+ autoCompletes: {
70
+ directoryPath: "./interactions/autoCompletes"
71
+ },
72
+ buttons: {
73
+ directoryPath: "./interactions/buttons"
74
+ },
75
+ commands: {
76
+ directoryPath: "./commands/slash"
77
+ },
78
+ contextMenus: {
79
+ directoryPath: "./commands/contextMenus"
80
+ },
81
+ events: {
82
+ directoryPath: "./events"
83
+ },
84
+ modals: {
85
+ directoryPath: "./interactions/modals"
86
+ },
87
+ selectMenus: {
88
+ directoryPath: "./interactions/selectMenus"
89
+ }
90
+ },
91
+ environment: {
92
+ areGuildsConfigurationEnabled: true
93
+ }
94
+ });
55
95
 
56
- const client = new StelliaClient(
57
- {
58
- intents: [
59
- GatewayIntentBits.Guilds,
60
- GatewayIntentBits.GuildMessages,
61
- GatewayIntentBits.MessageContent,
62
- GatewayIntentBits.GuildMembers
63
- ],
64
- partials: [Partials.Message, Partials.GuildMember]
65
- },
66
- {
67
- managers: {
68
- autoCompletes: {
69
- directoryPath: "./interactions/autoCompletes"
70
- },
71
- buttons: {
72
- directoryPath: "./interactions/buttons"
73
- },
74
- commands: {
75
- directoryPath: "./commands/slash"
76
- },
77
- contextMenus: {
78
- directoryPath: "./commands/contextMenus"
79
- },
80
- events: {
81
- directoryPath: "./events"
82
- },
83
- modals: {
84
- directoryPath: "./interactions/modals"
85
- },
86
- selectMenus: {
87
- directoryPath: "./interactions/selectMenus"
88
- }
89
- },
90
- environment: {
91
- areGuildsConfigurationEnabled: true
92
- }
93
- }
94
- );
95
-
96
- await client.connect(process.env.TOKEN);
96
+ await client.connect(process.env.TOKEN);
97
+ })();
97
98
  ```
98
99
 
99
- ### Simple event
100
+ #### Environment model
101
+
102
+ ```ts
103
+ import {
104
+ BaseGeneralConfiguration,
105
+ BaseGuildConfiguration,
106
+ GuildConfiguration,
107
+ GuildsConfiguration
108
+ } from "@stelliajs/framework";
109
+ import { Snowflake } from "discord.js";
110
+
111
+ interface MyBotGeneralConfiguration extends BaseGeneralConfiguration {
112
+ botName: string;
113
+ }
114
+ interface MyBotSpecificGuildConfiguration extends BaseGuildConfiguration {
115
+ channels: {
116
+ logs: Snowflake;
117
+ welcome: Snowflake;
118
+ };
119
+ }
120
+
121
+ export interface MyBotGuildConfiguration extends GuildConfiguration {
122
+ general: MyBotGeneralConfiguration;
123
+ guild: MyBotSpecificGuildConfiguration;
124
+ }
125
+
126
+ export interface MyBotGuildsConfiguration extends GuildsConfiguration {
127
+ general: MyBotGeneralConfiguration;
128
+ guilds: {
129
+ [guildId: Snowflake]: MyBotSpecificGuildConfiguration;
130
+ };
131
+ }
132
+ ```
100
133
 
101
- #### Ready event with environment
134
+ ### Interactions/Events with environment
102
135
 
103
- ```js
104
- import { type StelliaClient, type EventStructure } from "@stelliajs/framework";
136
+ #### Ready event
137
+
138
+ ```ts
139
+ import { type EventStructure, type StelliaClient } from "@stelliajs/framework";
105
140
  import { Events } from "discord.js";
106
- import { type CustomGuildsConfiguration } from "@environments/environment.model.ts";
141
+ import { type MyBotGuildsConfiguration } from "@environments/environment.model.ts";
107
142
 
108
143
  export default {
109
144
  data: {
110
145
  name: Events.ClientReady,
111
146
  once: true
112
147
  },
113
- async execute(client: StelliaClient<true>, environment: CustomGuildsConfiguration) { // <true> ensures that the client is Ready
148
+ async execute(client: StelliaClient<true>, guildsConfiguration: MyBotGuildsConfiguration) { // <true> ensures that the client is Ready
114
149
  console.log(`Logged in as ${client.user.tag}`);
115
150
  await client.initializeCommands(); // Used to initialise registered commands
116
151
  }
117
- } as EventStructure;
152
+ } satisfies EventStructure;
118
153
  ```
119
154
 
120
- #### InteractionCreate event with environment
155
+ #### InteractionCreate event
121
156
 
122
- ```js
157
+ ```ts
123
158
  import { type StelliaClient, type EventStructure } from "@stelliajs/framework";
124
159
  import { Events, type Interaction } from "discord.js";
125
- import { type CustomGuildsConfiguration } from "@environments/environment.model.ts";
160
+ import { type MyBotGuildConfiguration } from "@environments/environment.model.ts";
126
161
 
127
162
  export default {
128
163
  data: {
129
164
  name: Events.InteractionCreate,
130
165
  once: false
131
166
  },
132
- async execute(client: StelliaClient<true>, environment: CustomGuildsConfiguration, interaction: Interaction) {
167
+ async execute(client: StelliaClient<true>, guildConfiguration: MyBotGuildConfiguration, interaction: Interaction) {
133
168
  if (interaction.inCachedGuild()) {
134
169
  await client.handleInteraction(interaction); // Automatic interaction handling
135
170
  }
136
171
  }
137
- } as EventStructure;
172
+ } satisfies EventStructure;
138
173
  ```
139
174
 
140
- ### Simple command
175
+ #### Command interaction
141
176
 
142
- ```js
143
- import { type CommandStructure, ephemeralFollowUpResponse, type StelliaClient } from "@stelliajs/framework";
177
+ ```ts
178
+ import { type CommandStructure, type StelliaClient } from "@stelliajs/framework";
144
179
  import { type ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
145
- import { type CustomGuildsConfiguration } from "@environments/environment.model.ts";
180
+ import { type MyBotGuildConfiguration } from "@environments/environment.model.ts";
146
181
 
147
182
  export default {
148
- data: new SlashCommandBuilder()
149
- .setName("ping"),
150
- async execute(client: StelliaClient, environment: CustomGuildsConfiguration, interaction: ChatInputCommandInteraction<"cached">) { // All interactions are cached
151
- await ephemeralFollowUpResponse(interaction, "Pong!", true); // Response is ephemeral and deleted after 60 seconds
183
+ data: {
184
+ command: new SlashCommandBuilder()
185
+ .setName("ping"),
186
+ reply: {
187
+ autoDefer: true, // Defer the reply to avoid the interaction failing after 3 seconds
188
+ ephemeral: true, // The reply will be visible only by the user who triggered the interaction
189
+ }
190
+ },
191
+ async execute(client: StelliaClient, guildConfiguration: MyBotGuildConfiguration, interaction: ChatInputCommandInteraction<"cached">) { // All interactions are cached
192
+ await interaction.editReply("Pong!");
152
193
  }
153
- } as CommandStructure;
194
+ } satisfies CommandStructure;
154
195
  ```
155
196
 
156
197
  ## Help
@@ -2,20 +2,23 @@ import { Client, type ClientOptions, type Interaction } from "discord.js";
2
2
  import { type ManagerOptions } from "../managers/index.js";
3
3
  import { type ClientEnvironment, type GuildConfiguration, type GuildsConfiguration, type Managers } from "../typescript/index.js";
4
4
  export declare class StelliaClient<Ready extends boolean = boolean> extends Client<Ready> {
5
- private readonly utils;
5
+ private utils;
6
6
  readonly managers: Managers;
7
- readonly environment: ClientEnvironment;
8
- constructor(clientOptions: ClientOptions, stelliaOptions?: StelliaOptions);
7
+ readonly environment?: ClientEnvironment;
8
+ private constructor();
9
+ static create(clientOptions: ClientOptions, stelliaOptions?: StelliaOptions): Promise<StelliaClient>;
9
10
  connect: (token: string) => Promise<void>;
10
11
  initializeCommands: () => Promise<void>;
11
12
  getGuildsConfiguration: <CustomGuildsConfiguration extends GuildsConfiguration>() => Promise<CustomGuildsConfiguration>;
12
13
  getGuildConfiguration: <CustomGuildConfiguration extends GuildConfiguration>(guildId: string) => CustomGuildConfiguration | undefined;
13
14
  handleInteraction: (interaction: Interaction<"cached">) => Promise<void>;
15
+ private initializeAsyncFields;
16
+ private initializeManagers;
14
17
  private readonly areManagersLoaded;
15
18
  private static readonly convertFilePathToProduction;
16
19
  }
17
20
  interface StelliaOptions {
18
- managers: {
21
+ managers?: {
19
22
  autoCompletes?: ManagerOptions;
20
23
  buttons?: ManagerOptions;
21
24
  commands?: ManagerOptions;
@@ -1,4 +1,4 @@
1
- import * as fs from "node:fs";
1
+ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
4
  import { Client } from "discord.js";
@@ -14,28 +14,6 @@ export class StelliaClient extends Client {
14
14
  if (stelliaOptions?.environment) {
15
15
  this.environment = stelliaOptions.environment;
16
16
  }
17
- if (stelliaOptions?.managers.autoCompletes?.directoryPath) {
18
- this.managers.autoCompletes = new AutoCompleteManager(this, stelliaOptions.managers.autoCompletes.directoryPath);
19
- }
20
- if (stelliaOptions?.managers.buttons?.directoryPath) {
21
- this.managers.buttons = new ButtonManager(this, stelliaOptions.managers.buttons.directoryPath);
22
- }
23
- if (stelliaOptions?.managers.commands?.directoryPath) {
24
- this.managers.commands = new CommandManager(this, stelliaOptions.managers.commands.directoryPath);
25
- }
26
- if (stelliaOptions?.managers.contextMenus?.directoryPath) {
27
- this.managers.contextMenus = new ContextMenuManager(this, stelliaOptions.managers.contextMenus.directoryPath);
28
- }
29
- if (stelliaOptions?.managers.events?.directoryPath) {
30
- this.managers.events = new EventManager(this, stelliaOptions.managers.events.directoryPath);
31
- }
32
- if (stelliaOptions?.managers.selectMenus?.directoryPath) {
33
- this.managers.selectMenus = new SelectMenuManager(this, stelliaOptions.managers.selectMenus.directoryPath);
34
- }
35
- if (stelliaOptions?.managers.modals?.directoryPath) {
36
- this.managers.modals = new ModalManager(this, stelliaOptions.managers.modals.directoryPath);
37
- }
38
- this.utils = new StelliaUtils(this);
39
17
  process.on("unhandledRejection", (error) => {
40
18
  logger.error(`Unhandled promise rejection: ${error.stack}`);
41
19
  });
@@ -43,6 +21,11 @@ export class StelliaClient extends Client {
43
21
  logger.error(`Uncaught exception: ${error.stack}`);
44
22
  });
45
23
  }
24
+ static async create(clientOptions, stelliaOptions) {
25
+ const client = new StelliaClient(clientOptions, stelliaOptions);
26
+ await client.initializeAsyncFields(stelliaOptions);
27
+ return client;
28
+ }
46
29
  connect = async (token) => {
47
30
  if (!this.areManagersLoaded()) {
48
31
  setTimeout(() => {
@@ -90,6 +73,38 @@ export class StelliaClient extends Client {
90
73
  handleInteraction = async (interaction) => {
91
74
  await this.utils.handleInteraction(interaction);
92
75
  };
76
+ async initializeAsyncFields(stelliaOptions) {
77
+ this.utils = await StelliaUtils.create(this);
78
+ await this.initializeManagers(stelliaOptions?.managers);
79
+ }
80
+ ;
81
+ async initializeManagers(managers) {
82
+ if (!managers) {
83
+ return;
84
+ }
85
+ if (managers.autoCompletes?.directoryPath) {
86
+ this.managers.autoCompletes = await AutoCompleteManager.create(this, managers.autoCompletes.directoryPath);
87
+ }
88
+ if (managers.buttons?.directoryPath) {
89
+ this.managers.buttons = await ButtonManager.create(this, managers.buttons.directoryPath);
90
+ }
91
+ if (managers.commands?.directoryPath) {
92
+ this.managers.commands = await CommandManager.create(this, managers.commands.directoryPath);
93
+ }
94
+ if (managers.contextMenus?.directoryPath) {
95
+ this.managers.contextMenus = await ContextMenuManager.create(this, managers.contextMenus.directoryPath);
96
+ }
97
+ if (managers.events?.directoryPath) {
98
+ this.managers.events = await EventManager.create(this, managers.events.directoryPath);
99
+ }
100
+ if (managers.selectMenus?.directoryPath) {
101
+ this.managers.selectMenus = await SelectMenuManager.create(this, managers.selectMenus.directoryPath);
102
+ }
103
+ if (managers.modals?.directoryPath) {
104
+ this.managers.modals = await ModalManager.create(this, managers.modals.directoryPath);
105
+ }
106
+ }
107
+ ;
93
108
  areManagersLoaded = () => {
94
109
  const managers = Object.values(this.managers);
95
110
  return managers.length === 0
@@ -5,10 +5,12 @@ export declare class StelliaUtils {
5
5
  readonly client: StelliaClient;
6
6
  private readonly interactionHandlers;
7
7
  private guildsConfiguration;
8
- constructor(client: StelliaClient);
8
+ private constructor();
9
+ static create(client: StelliaClient): Promise<StelliaUtils>;
9
10
  initializeCommands: () => Promise<void>;
10
11
  getGuildConfiguration: <CustomGuildConfiguration extends GuildConfiguration>(guildId: string) => CustomGuildConfiguration | undefined;
11
12
  handleInteraction: (interaction: Interaction<"cached">) => Promise<void>;
13
+ private initializeGuildsConfiguration;
12
14
  private readonly handleAutoCompleteInteraction;
13
15
  private readonly handleButtonInteraction;
14
16
  private readonly handleCommandInteraction;
@@ -16,16 +16,14 @@ export class StelliaUtils {
16
16
  [InteractionType.ModalSubmit, this.handleModalInteraction],
17
17
  [InteractionType.SelectMenu, this.handleSelectMenuInteraction]
18
18
  ]);
19
- if (this.client.environment.areGuildsConfigurationEnabled) {
20
- this.client
21
- .getGuildsConfiguration()
22
- .then((guildsConfiguration) => {
23
- this.guildsConfiguration = guildsConfiguration;
24
- logger.success("Guilds configuration loaded successfully for interactions");
25
- })
26
- .catch((error) => logger.error(`Error while loading guilds configuration: ${error.stack}`));
27
- }
28
19
  }
20
+ ;
21
+ static async create(client) {
22
+ const utils = new StelliaUtils(client);
23
+ await utils.initializeGuildsConfiguration();
24
+ return utils;
25
+ }
26
+ ;
29
27
  initializeCommands = async () => {
30
28
  const commands = this.client.managers.commands?.getAll().values();
31
29
  const contextMenus = this.client.managers.contextMenus?.getAll().values();
@@ -44,7 +42,7 @@ export class StelliaUtils {
44
42
  }
45
43
  };
46
44
  getGuildConfiguration = (guildId) => {
47
- if (!this.client.environment.areGuildsConfigurationEnabled || !this.guildsConfiguration) {
45
+ if (!this.client.environment?.areGuildsConfigurationEnabled || !this.guildsConfiguration) {
48
46
  return undefined;
49
47
  }
50
48
  const { guilds, general } = this.guildsConfiguration;
@@ -66,6 +64,19 @@ export class StelliaUtils {
66
64
  }
67
65
  }
68
66
  };
67
+ async initializeGuildsConfiguration() {
68
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
69
+ try {
70
+ const guildsConfiguration = await this.client.getGuildsConfiguration();
71
+ this.guildsConfiguration = guildsConfiguration;
72
+ logger.success("Guilds configuration loaded successfully for interactions");
73
+ }
74
+ catch (error) {
75
+ logger.error(`Error while loading guilds configuration: ${error.stack}`);
76
+ }
77
+ }
78
+ }
79
+ ;
69
80
  handleAutoCompleteInteraction = async (interaction) => {
70
81
  try {
71
82
  const autoCompleteInteraction = interaction;
@@ -75,7 +86,7 @@ export class StelliaUtils {
75
86
  const autoComplete = autoCompleteManager.getByCustomId(autoCompleteInteraction.commandName);
76
87
  if (!autoComplete)
77
88
  return;
78
- if (this.client.environment.areGuildsConfigurationEnabled) {
89
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
79
90
  const autoCompleteWithGuildConfiguration = autoComplete;
80
91
  const guildConfiguration = this.getGuildConfiguration(autoCompleteInteraction.guildId);
81
92
  await autoCompleteWithGuildConfiguration.execute(this.client, guildConfiguration, autoCompleteInteraction);
@@ -102,7 +113,7 @@ export class StelliaUtils {
102
113
  if (button.data.reply.autoDefer && !buttonInteraction.deferred) {
103
114
  await buttonInteraction.deferReply({ flags: button.data.reply.ephemeral ? MessageFlags.Ephemeral : undefined });
104
115
  }
105
- if (this.client.environment.areGuildsConfigurationEnabled) {
116
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
106
117
  const buttonWithGuildConfiguration = button;
107
118
  const guildConfiguration = this.getGuildConfiguration(buttonInteraction.guildId);
108
119
  await buttonWithGuildConfiguration.execute(this.client, guildConfiguration, buttonInteraction);
@@ -128,7 +139,7 @@ export class StelliaUtils {
128
139
  if (command.data.reply.autoDefer && !commandInteraction.deferred) {
129
140
  await commandInteraction.deferReply({ flags: command.data.reply.ephemeral ? MessageFlags.Ephemeral : undefined });
130
141
  }
131
- if (this.client.environment.areGuildsConfigurationEnabled) {
142
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
132
143
  const commandWithGuildConfiguration = command;
133
144
  const guildConfiguration = this.getGuildConfiguration(commandInteraction.guildId);
134
145
  await commandWithGuildConfiguration.execute(this.client, guildConfiguration, commandInteraction);
@@ -171,7 +182,7 @@ export class StelliaUtils {
171
182
  if (modal.data.reply.autoDefer && !modalInteraction.deferred) {
172
183
  await modalInteraction.deferReply({ flags: modal.data.reply.ephemeral ? MessageFlags.Ephemeral : undefined });
173
184
  }
174
- if (this.client.environment.areGuildsConfigurationEnabled) {
185
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
175
186
  const modalWithGuildConfiguration = modal;
176
187
  const guildConfiguration = this.getGuildConfiguration(modalInteraction.guildId);
177
188
  await modalWithGuildConfiguration.execute(this.client, guildConfiguration, modalInteraction);
@@ -198,7 +209,7 @@ export class StelliaUtils {
198
209
  if (selectMenu.data.reply.autoDefer && !selectMenuInteraction.deferred) {
199
210
  await selectMenuInteraction.deferReply({ flags: selectMenu.data.reply.ephemeral ? MessageFlags.Ephemeral : undefined });
200
211
  }
201
- if (this.client.environment.areGuildsConfigurationEnabled) {
212
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
202
213
  const selectMenuWithGuildConfiguration = selectMenu;
203
214
  const guildConfiguration = this.getGuildConfiguration(selectMenuInteraction.guildId);
204
215
  await selectMenuWithGuildConfiguration.execute(this.client, guildConfiguration, selectMenuInteraction);
@@ -223,7 +234,7 @@ export class StelliaUtils {
223
234
  if (messageContextMenu.data.reply.autoDefer && !interaction.deferred) {
224
235
  await interaction.deferReply({ flags: messageContextMenu.data.reply.ephemeral ? MessageFlags.Ephemeral : undefined });
225
236
  }
226
- if (this.client.environment.areGuildsConfigurationEnabled) {
237
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
227
238
  const messageContextMenuWithGuildConfiguration = messageContextMenu;
228
239
  const guildConfiguration = this.getGuildConfiguration(interaction.guildId);
229
240
  await messageContextMenuWithGuildConfiguration.execute(this.client, guildConfiguration, interaction);
@@ -248,7 +259,7 @@ export class StelliaUtils {
248
259
  if (userContextMenu.data.reply.autoDefer && !interaction.deferred) {
249
260
  await interaction.deferReply({ flags: userContextMenu.data.reply.ephemeral ? MessageFlags.Ephemeral : undefined });
250
261
  }
251
- if (this.client.environment.areGuildsConfigurationEnabled) {
262
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
252
263
  const userContextMenuWithGuildConfiguration = userContextMenu;
253
264
  const guildConfiguration = this.getGuildConfiguration(interaction.guildId);
254
265
  await userContextMenuWithGuildConfiguration.execute(this.client, guildConfiguration, interaction);
@@ -4,7 +4,8 @@ import { BaseManager } from "./index.js";
4
4
  import { type InteractionCustomId, type StructureCustomId } from "../typescript/index.js";
5
5
  export declare class AutoCompleteManager extends BaseManager {
6
6
  private interactions;
7
- constructor(client: StelliaClient, directory: string);
7
+ private constructor();
8
+ static create(client: StelliaClient, directory: string): Promise<AutoCompleteManager>;
8
9
  loadData(): Promise<void>;
9
10
  getByCustomId<AutoCompleteStructure>(id: InteractionCustomId): AutoCompleteStructure | null;
10
11
  getByRegex<AutoCompleteStructure>(id: InteractionCustomId): AutoCompleteStructure | null;
@@ -3,8 +3,13 @@ import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
4
  export class AutoCompleteManager extends BaseManager {
5
5
  interactions = new Collection();
6
- constructor(client, directory) {
7
- super(client, directory);
6
+ constructor(client, directoryPath) {
7
+ super(client, directoryPath);
8
+ }
9
+ static async create(client, directory) {
10
+ const manager = new AutoCompleteManager(client, directory);
11
+ await manager.loadData();
12
+ return manager;
8
13
  }
9
14
  async loadData() {
10
15
  const autoCompletes = await requiredFiles(this.directoryPath);
@@ -9,7 +9,7 @@ export declare abstract class BaseManager {
9
9
  readonly client: StelliaClient;
10
10
  readonly directoryPath: string;
11
11
  private isLoaded;
12
- constructor(client: StelliaClient, directory: string);
12
+ protected constructor(client: StelliaClient, directory: string);
13
13
  isManagerLoaded(): boolean;
14
14
  setManagerLoaded(): void;
15
15
  abstract loadData(): Promise<void>;
@@ -5,7 +5,6 @@ export class BaseManager {
5
5
  constructor(client, directory) {
6
6
  this.client = client;
7
7
  this.directoryPath = directory;
8
- this.loadData();
9
8
  }
10
9
  isManagerLoaded() {
11
10
  return this.isLoaded;
@@ -5,7 +5,8 @@ import { type ButtonStructure } from "../structures/index.js";
5
5
  import { type InteractionCustomId, type StructureCustomId } from "../typescript/index.js";
6
6
  export declare class ButtonManager extends BaseManager {
7
7
  interactions: Collection<StructureCustomId, ButtonStructure>;
8
- constructor(client: StelliaClient, directory: string);
8
+ private constructor();
9
+ static create(client: StelliaClient, directory: string): Promise<ButtonManager>;
9
10
  loadData(): Promise<void>;
10
11
  getByCustomId<ButtonStructure>(id: InteractionCustomId): ButtonStructure | null;
11
12
  getByRegex<ButtonStructure>(id: InteractionCustomId): ButtonStructure | null;
@@ -3,8 +3,13 @@ import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
4
  export class ButtonManager extends BaseManager {
5
5
  interactions = new Collection();
6
- constructor(client, directory) {
7
- super(client, directory);
6
+ constructor(client, directoryPath) {
7
+ super(client, directoryPath);
8
+ }
9
+ static async create(client, directory) {
10
+ const manager = new ButtonManager(client, directory);
11
+ await manager.loadData();
12
+ return manager;
8
13
  }
9
14
  async loadData() {
10
15
  const buttons = await requiredFiles(this.directoryPath);
@@ -4,7 +4,8 @@ import { BaseManager } from "./index.js";
4
4
  import { type InteractionCustomId, type StructureCustomId } from "../typescript/index.js";
5
5
  export declare class CommandManager extends BaseManager {
6
6
  private interactions;
7
- constructor(client: StelliaClient, directory: string);
7
+ private constructor();
8
+ static create(client: StelliaClient, directory: string): Promise<CommandManager>;
8
9
  loadData(): Promise<void>;
9
10
  getByCustomId<CommandStructure>(id: InteractionCustomId): CommandStructure | null;
10
11
  getByRegex<CommandStructure>(id: InteractionCustomId): CommandStructure | null;
@@ -3,8 +3,13 @@ import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
4
  export class CommandManager extends BaseManager {
5
5
  interactions = new Collection();
6
- constructor(client, directory) {
7
- super(client, directory);
6
+ constructor(client, directoryPath) {
7
+ super(client, directoryPath);
8
+ }
9
+ static async create(client, directory) {
10
+ const manager = new CommandManager(client, directory);
11
+ await manager.loadData();
12
+ return manager;
8
13
  }
9
14
  async loadData() {
10
15
  const commands = await requiredFiles(this.directoryPath);
@@ -4,7 +4,8 @@ import { BaseManager } from "./index.js";
4
4
  import { type InteractionCustomId, type StructureCustomId } from "../typescript/index.js";
5
5
  export declare class ContextMenuManager extends BaseManager {
6
6
  private interactions;
7
- constructor(client: StelliaClient, directory: string);
7
+ private constructor();
8
+ static create(client: StelliaClient, directory: string): Promise<ContextMenuManager>;
8
9
  loadData(): Promise<void>;
9
10
  getByCustomId<ContextMenuStructure>(id: InteractionCustomId): ContextMenuStructure | null;
10
11
  getByRegex<ContextMenuStructure>(id: InteractionCustomId): ContextMenuStructure | null;
@@ -3,8 +3,13 @@ import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
4
  export class ContextMenuManager extends BaseManager {
5
5
  interactions = new Collection();
6
- constructor(client, directory) {
7
- super(client, directory);
6
+ constructor(client, directoryPath) {
7
+ super(client, directoryPath);
8
+ }
9
+ static async create(client, directory) {
10
+ const manager = new ContextMenuManager(client, directory);
11
+ await manager.loadData();
12
+ return manager;
8
13
  }
9
14
  async loadData() {
10
15
  const contextMenus = await requiredFiles(this.directoryPath);
@@ -5,7 +5,8 @@ import { type InteractionCustomId, type StructureCustomId } from "../typescript/
5
5
  export declare class EventManager extends BaseManager {
6
6
  private interactions;
7
7
  private guildsConfiguration;
8
- constructor(client: StelliaClient, directoryPath: string);
8
+ private constructor();
9
+ static create(client: StelliaClient, directoryPath: string): Promise<EventManager>;
9
10
  loadData(): Promise<void>;
10
11
  getByCustomId<EventStructure>(id: InteractionCustomId): EventStructure | null;
11
12
  getByRegex<EventStructure>(id: InteractionCustomId): EventStructure | null;
@@ -14,4 +15,5 @@ export declare class EventManager extends BaseManager {
14
15
  private readonly eventHandler;
15
16
  private loadEventWithoutGuildConfiguration;
16
17
  private getGuildConfiguration;
18
+ private initializeGuildsConfiguration;
17
19
  }
@@ -7,21 +7,19 @@ export class EventManager extends BaseManager {
7
7
  guildsConfiguration;
8
8
  constructor(client, directoryPath) {
9
9
  super(client, directoryPath);
10
- if (this.client.environment.areGuildsConfigurationEnabled) {
11
- this.client
12
- .getGuildsConfiguration()
13
- .then((guildsConfiguration) => {
14
- this.guildsConfiguration = guildsConfiguration;
15
- logger.success("Guilds configuration loaded successfully for event");
16
- })
17
- .catch((error) => logger.error(`Error while loading guilds configuration: ${error.stack}`));
18
- }
19
10
  }
11
+ static async create(client, directoryPath) {
12
+ const manager = new EventManager(client, directoryPath);
13
+ await manager.loadData();
14
+ await manager.initializeGuildsConfiguration();
15
+ return manager;
16
+ }
17
+ ;
20
18
  async loadData() {
21
19
  const events = await requiredFiles(this.directoryPath);
22
20
  this.interactions = events;
23
21
  for (const eventStructure of this.interactions.values()) {
24
- if (this.client.environment.areGuildsConfigurationEnabled) {
22
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
25
23
  await this.loadEventWithGuildConfiguration(eventStructure);
26
24
  }
27
25
  else {
@@ -58,6 +56,7 @@ export class EventManager extends BaseManager {
58
56
  this.client.on(name, (...args) => this.eventHandler(event, ...args));
59
57
  }
60
58
  }
59
+ ;
61
60
  eventHandler = (event, ...args) => {
62
61
  const mainArgument = args[0];
63
62
  const guildConfiguration = this.getGuildConfiguration(mainArgument);
@@ -78,6 +77,7 @@ export class EventManager extends BaseManager {
78
77
  this.client.on(name, (...args) => event.execute(this.client, ...args));
79
78
  }
80
79
  }
80
+ ;
81
81
  getGuildConfiguration(mainArgument) {
82
82
  if (mainArgument && typeof mainArgument === "object") {
83
83
  if ("guildId" in mainArgument && mainArgument.guildId) {
@@ -89,4 +89,18 @@ export class EventManager extends BaseManager {
89
89
  }
90
90
  return undefined;
91
91
  }
92
+ ;
93
+ async initializeGuildsConfiguration() {
94
+ if (this.client.environment?.areGuildsConfigurationEnabled) {
95
+ try {
96
+ const guildsConfiguration = await this.client.getGuildsConfiguration();
97
+ this.guildsConfiguration = guildsConfiguration;
98
+ logger.success("Guilds configuration loaded successfully for events");
99
+ }
100
+ catch (error) {
101
+ logger.error(`Error while loading guilds configuration: ${error.stack}`);
102
+ }
103
+ }
104
+ }
105
+ ;
92
106
  }
@@ -4,7 +4,8 @@ import { BaseManager } from "./index.js";
4
4
  import { type InteractionCustomId, type StructureCustomId } from "../typescript/index.js";
5
5
  export declare class ModalManager extends BaseManager {
6
6
  private interactions;
7
- constructor(client: StelliaClient, directory: string);
7
+ private constructor();
8
+ static create(client: StelliaClient, directory: string): Promise<ModalManager>;
8
9
  loadData(): Promise<void>;
9
10
  getByCustomId<ModalStructure>(id: InteractionCustomId): ModalStructure | null;
10
11
  getByRegex<ModalStructure>(id: InteractionCustomId): ModalStructure | null;
@@ -3,8 +3,13 @@ import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
4
  export class ModalManager extends BaseManager {
5
5
  interactions = new Collection();
6
- constructor(client, directory) {
7
- super(client, directory);
6
+ constructor(client, directoryPath) {
7
+ super(client, directoryPath);
8
+ }
9
+ static async create(client, directory) {
10
+ const manager = new ModalManager(client, directory);
11
+ await manager.loadData();
12
+ return manager;
8
13
  }
9
14
  async loadData() {
10
15
  const modals = await requiredFiles(this.directoryPath);
@@ -4,7 +4,8 @@ import { BaseManager } from "./index.js";
4
4
  import { type InteractionCustomId, type StructureCustomId } from "../typescript/index.js";
5
5
  export declare class SelectMenuManager extends BaseManager {
6
6
  private interactions;
7
- constructor(client: StelliaClient, directory: string);
7
+ private constructor();
8
+ static create(client: StelliaClient, directory: string): Promise<SelectMenuManager>;
8
9
  loadData(): Promise<void>;
9
10
  getByCustomId<SelectMenuStructure>(id: InteractionCustomId): SelectMenuStructure | null;
10
11
  getByRegex<SelectMenuStructure>(id: InteractionCustomId): SelectMenuStructure | null;
@@ -3,8 +3,13 @@ import { BaseManager } from "./index.js";
3
3
  import { requiredFiles } from "../utils/index.js";
4
4
  export class SelectMenuManager extends BaseManager {
5
5
  interactions = new Collection();
6
- constructor(client, directory) {
7
- super(client, directory);
6
+ constructor(client, directoryPath) {
7
+ super(client, directoryPath);
8
+ }
9
+ static async create(client, directory) {
10
+ const manager = new SelectMenuManager(client, directory);
11
+ await manager.loadData();
12
+ return manager;
8
13
  }
9
14
  async loadData() {
10
15
  const selectMenus = await requiredFiles(this.directoryPath);
@@ -1,15 +1,16 @@
1
1
  import logSymbols from "log-symbols";
2
+ const prefix = "[StelliaJS]";
2
3
  export const logger = {
3
4
  info: (message) => {
4
- console.log(`${logSymbols.info} ${message}`);
5
+ console.log(`${logSymbols.info} ${prefix} ${message}`);
5
6
  },
6
7
  success: (message) => {
7
- console.log(`${logSymbols.success} ${message}`);
8
+ console.log(`${logSymbols.success} ${prefix} ${message}`);
8
9
  },
9
10
  warn: (message) => {
10
- console.warn(`${logSymbols.warning} ${message}`);
11
+ console.warn(`${logSymbols.warning} ${prefix} ${message}`);
11
12
  },
12
13
  error: (message) => {
13
- console.error(`${logSymbols.error} ${message}`);
14
+ console.error(`${logSymbols.error} ${prefix} ${message}`);
14
15
  }
15
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stelliajs/framework",
3
- "version": "1.5.4",
3
+ "version": "1.5.7",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "scripts": {
@@ -23,19 +23,19 @@
23
23
  "framework"
24
24
  ],
25
25
  "dependencies": {
26
- "discord.js": "^14.22.1",
27
- "i18next": "^25.5.2",
26
+ "discord.js": "^14.24.0",
27
+ "i18next": "^25.6.0",
28
28
  "log-symbols": "^7.0.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@eslint/js": "^9.36.0",
31
+ "@eslint/js": "^9.38.0",
32
32
  "eslint-config-prettier": "^10.1.8",
33
33
  "eslint-import-resolver-typescript": "^4.4.4",
34
34
  "eslint-plugin-import": "^2.32.0",
35
35
  "prettier": "^3.6.2",
36
36
  "tsc-alias": "^1.8.16",
37
- "typescript-eslint": "^8.44.1"
37
+ "typescript-eslint": "^8.46.2"
38
38
  },
39
39
  "type": "module",
40
- "packageManager": "pnpm@10.17.1"
40
+ "packageManager": "pnpm@10.19.0"
41
41
  }
package/.prettierrc DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "semi": true,
3
- "singleQuote": false,
4
- "useTabs": true,
5
- "tabWidth": 2,
6
- "trailingComma": "none",
7
- "printWidth": 100
8
- }
package/eslint.config.mjs DELETED
@@ -1,68 +0,0 @@
1
- import js from "@eslint/js";
2
- import ts from "typescript-eslint";
3
- import importPlugin from "eslint-plugin-import";
4
- import prettierConfig from "eslint-config-prettier";
5
-
6
- export default ts.config(
7
- js.configs.recommended,
8
- ts.configs.recommended,
9
- importPlugin.flatConfigs.recommended,
10
- importPlugin.flatConfigs.typescript,
11
- prettierConfig,
12
- {
13
- languageOptions: {
14
- parserOptions: {
15
- project: "./tsconfig.json",
16
- sourceType: "module",
17
- ecmaVersion: "latest"
18
- }
19
- },
20
- rules: {
21
- "import/namespace": "off",
22
- "@typescript-eslint/explicit-function-return-type": "off",
23
- "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
24
- "@typescript-eslint/no-explicit-any": "warn",
25
- "import/order": [
26
- "error",
27
- {
28
- groups: [
29
- "builtin",
30
- "external",
31
- "internal",
32
- ["parent", "sibling", "index"],
33
- "object",
34
- "type"
35
- ],
36
- pathGroups: [
37
- {
38
- pattern: "@/**",
39
- group: "internal"
40
- }
41
- ],
42
- pathGroupsExcludedImportTypes: ["builtin"],
43
- alphabetize: {
44
- order: "asc",
45
- caseInsensitive: true
46
- }
47
- }
48
- ],
49
- "import/newline-after-import": ["error", { count: 1 }],
50
- "import/no-unresolved": "error",
51
- "import/no-duplicates": "error",
52
- "no-console": "off",
53
- "no-var": "error",
54
- "prefer-const": "error"
55
- },
56
- settings: {
57
- "import/resolver": {
58
- typescript: {
59
- alwaysTryTypes: true,
60
- project: "./tsconfig.json"
61
- },
62
- node: {
63
- extensions: [".js", ".ts"]
64
- }
65
- }
66
- }
67
- }
68
- );