@spatulox/simplediscordbot 2.0.3 → 2.1.1

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/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Changelog
2
2
  Date format : dd/mm/yyy
3
3
 
4
+ ### 15/04/2026 - 2.1.0
5
+ - Add a CacheManager for simple persisting data
6
+ - Add QoL method to FileManager (fileExist(), deleteFile())
7
+ - Fix :
8
+ - SimpleDiscordBotInfo.version showing license instead of version
9
+ - FileManager should be able to create hidden folder
10
+
11
+ ### 13/04/2026 - 2.0.3
12
+ - Fix : WebhookManager can now send webhooks in threads
13
+
4
14
  ### 08/04/2026 - 2.0.1
5
15
  - Fix the README.md to match the new BotLog system
6
16
 
package/dist/index.d.mts CHANGED
@@ -160,6 +160,12 @@ declare const BotEnv: {
160
160
  };
161
161
 
162
162
  declare class FileManager {
163
+ /**
164
+ * Check if a file exist
165
+ * @param filePath File path with file name
166
+ * @returns true si le fichier existe, false sinon
167
+ */
168
+ static fileExists(filePath: string): Promise<boolean>;
163
169
  /**
164
170
  * Reads a JSON file synchronously.
165
171
  * @param filePath Full path to the JSON file
@@ -194,6 +200,77 @@ declare class FileManager {
194
200
  * @returns true on success, false on failure
195
201
  */
196
202
  static writeJsonFile(directoryPath: string, filename: string, data: any, sendErrorToErrorChannel?: boolean): Promise<boolean>;
203
+ /**
204
+ * Delete a file
205
+ * @param filePath Full file path
206
+ * @returns true si supprimé avec succès, false sinon
207
+ */
208
+ static deleteFile(filePath: string): Promise<boolean>;
209
+ }
210
+
211
+ declare class CacheManager {
212
+ private static get cacheDir();
213
+ private static cleanCacheId;
214
+ private static createFilePath;
215
+ /**
216
+ * New file with cache_id as name
217
+ * @param cache_id - id which become the cache file name
218
+ * @param initialData - optional initial data
219
+ * @returns true if success, false otherwise
220
+ */
221
+ static createCache(cache_id: string, initialData?: any): Promise<boolean>;
222
+ /**
223
+ * Read cache data or create empty one
224
+ * @param cache_id
225
+ * @param default_data default data with default key/value This will be send back if the cache doesn't exist and need to be created
226
+ * @returns true if success, false otherwise
227
+ */
228
+ static getOrCreateCache<T = any>(cache_id: string, default_data: T): Promise<T | false>;
229
+ /**
230
+ * Read cache data
231
+ * @param cache_id - cache_id to read
232
+ * @returns Json data, false otherwise
233
+ */
234
+ static readCache<T = any>(cache_id: string): Promise<T | false>;
235
+ /**
236
+ * Overwrite cache data with the new data
237
+ * @param cache_id - ID of the cache
238
+ * @param data - new data
239
+ * @returns true if success, false otherwise
240
+ */
241
+ static writeCache(cache_id: string, data: any): Promise<boolean>;
242
+ /**
243
+ * Update specific property of the cache
244
+ * @param cache_id - ID of the cache
245
+ * @param property - property to update, with key and value
246
+ * @returns true if success, false otherwise
247
+ */
248
+ static updateCacheProperty(cache_id: string, property: {
249
+ key: string;
250
+ value: any;
251
+ }): Promise<boolean>;
252
+ /**
253
+ * Reset an entire cache
254
+ * @param cache_id - cache ID to reset
255
+ * @returns true if success, false otherwise
256
+ */
257
+ static resetCache(cache_id: string): Promise<boolean>;
258
+ /**
259
+ * Delete an entire cache
260
+ * @param cache_id - cache ID to delete
261
+ * @returns true if success, false otherwise
262
+ */
263
+ static deleteCache(cache_id: string): Promise<boolean>;
264
+ /**
265
+ * List every existing cache
266
+ * @returns Array of cache_id, false otherwise
267
+ */
268
+ static listCaches(): Promise<string[] | false>;
269
+ /**
270
+ * Clean cache data
271
+ * @returns true if success, false otherwise
272
+ */
273
+ static clearAllCaches(): Promise<boolean>;
197
274
  }
198
275
 
199
276
  declare class EmbedManager {
@@ -1083,4 +1160,4 @@ declare const SimpleDiscordBotInfo: {
1083
1160
  license: string;
1084
1161
  };
1085
1162
 
1086
- export { Bot, type BotConfig, BotEnv, ButtonManager, type ButtonOptions, ComponentManager, type ComponentManagerCreate, type ComponentManagerField, type ComponentManagerFileInput, DiscordRegex, EmbedManager, FileManager, GuildManager, Log, type ModalField, ModalFieldType, ModalManager, type RandomBotActivity, ReactionManager, type SelectMenuCreateOption, type SelectMenuList, SelectMenuManager, SimpleColor, SimpleDiscordBotInfo, SimpleMutex, Time, UserManager, WebhookManager };
1163
+ export { Bot, type BotConfig, BotEnv, ButtonManager, type ButtonOptions, CacheManager, ComponentManager, type ComponentManagerCreate, type ComponentManagerField, type ComponentManagerFileInput, DiscordRegex, EmbedManager, FileManager, GuildManager, Log, type ModalField, ModalFieldType, ModalManager, type RandomBotActivity, ReactionManager, type SelectMenuCreateOption, type SelectMenuList, SelectMenuManager, SimpleColor, SimpleDiscordBotInfo, SimpleMutex, Time, UserManager, WebhookManager };
package/dist/index.d.ts CHANGED
@@ -160,6 +160,12 @@ declare const BotEnv: {
160
160
  };
161
161
 
162
162
  declare class FileManager {
163
+ /**
164
+ * Check if a file exist
165
+ * @param filePath File path with file name
166
+ * @returns true si le fichier existe, false sinon
167
+ */
168
+ static fileExists(filePath: string): Promise<boolean>;
163
169
  /**
164
170
  * Reads a JSON file synchronously.
165
171
  * @param filePath Full path to the JSON file
@@ -194,6 +200,77 @@ declare class FileManager {
194
200
  * @returns true on success, false on failure
195
201
  */
196
202
  static writeJsonFile(directoryPath: string, filename: string, data: any, sendErrorToErrorChannel?: boolean): Promise<boolean>;
203
+ /**
204
+ * Delete a file
205
+ * @param filePath Full file path
206
+ * @returns true si supprimé avec succès, false sinon
207
+ */
208
+ static deleteFile(filePath: string): Promise<boolean>;
209
+ }
210
+
211
+ declare class CacheManager {
212
+ private static get cacheDir();
213
+ private static cleanCacheId;
214
+ private static createFilePath;
215
+ /**
216
+ * New file with cache_id as name
217
+ * @param cache_id - id which become the cache file name
218
+ * @param initialData - optional initial data
219
+ * @returns true if success, false otherwise
220
+ */
221
+ static createCache(cache_id: string, initialData?: any): Promise<boolean>;
222
+ /**
223
+ * Read cache data or create empty one
224
+ * @param cache_id
225
+ * @param default_data default data with default key/value This will be send back if the cache doesn't exist and need to be created
226
+ * @returns true if success, false otherwise
227
+ */
228
+ static getOrCreateCache<T = any>(cache_id: string, default_data: T): Promise<T | false>;
229
+ /**
230
+ * Read cache data
231
+ * @param cache_id - cache_id to read
232
+ * @returns Json data, false otherwise
233
+ */
234
+ static readCache<T = any>(cache_id: string): Promise<T | false>;
235
+ /**
236
+ * Overwrite cache data with the new data
237
+ * @param cache_id - ID of the cache
238
+ * @param data - new data
239
+ * @returns true if success, false otherwise
240
+ */
241
+ static writeCache(cache_id: string, data: any): Promise<boolean>;
242
+ /**
243
+ * Update specific property of the cache
244
+ * @param cache_id - ID of the cache
245
+ * @param property - property to update, with key and value
246
+ * @returns true if success, false otherwise
247
+ */
248
+ static updateCacheProperty(cache_id: string, property: {
249
+ key: string;
250
+ value: any;
251
+ }): Promise<boolean>;
252
+ /**
253
+ * Reset an entire cache
254
+ * @param cache_id - cache ID to reset
255
+ * @returns true if success, false otherwise
256
+ */
257
+ static resetCache(cache_id: string): Promise<boolean>;
258
+ /**
259
+ * Delete an entire cache
260
+ * @param cache_id - cache ID to delete
261
+ * @returns true if success, false otherwise
262
+ */
263
+ static deleteCache(cache_id: string): Promise<boolean>;
264
+ /**
265
+ * List every existing cache
266
+ * @returns Array of cache_id, false otherwise
267
+ */
268
+ static listCaches(): Promise<string[] | false>;
269
+ /**
270
+ * Clean cache data
271
+ * @returns true if success, false otherwise
272
+ */
273
+ static clearAllCaches(): Promise<boolean>;
197
274
  }
198
275
 
199
276
  declare class EmbedManager {
@@ -1083,4 +1160,4 @@ declare const SimpleDiscordBotInfo: {
1083
1160
  license: string;
1084
1161
  };
1085
1162
 
1086
- export { Bot, type BotConfig, BotEnv, ButtonManager, type ButtonOptions, ComponentManager, type ComponentManagerCreate, type ComponentManagerField, type ComponentManagerFileInput, DiscordRegex, EmbedManager, FileManager, GuildManager, Log, type ModalField, ModalFieldType, ModalManager, type RandomBotActivity, ReactionManager, type SelectMenuCreateOption, type SelectMenuList, SelectMenuManager, SimpleColor, SimpleDiscordBotInfo, SimpleMutex, Time, UserManager, WebhookManager };
1163
+ export { Bot, type BotConfig, BotEnv, ButtonManager, type ButtonOptions, CacheManager, ComponentManager, type ComponentManagerCreate, type ComponentManagerField, type ComponentManagerFileInput, DiscordRegex, EmbedManager, FileManager, GuildManager, Log, type ModalField, ModalFieldType, ModalManager, type RandomBotActivity, ReactionManager, type SelectMenuCreateOption, type SelectMenuList, SelectMenuManager, SimpleColor, SimpleDiscordBotInfo, SimpleMutex, Time, UserManager, WebhookManager };
package/dist/index.js CHANGED
@@ -863,11 +863,11 @@ var require_baseGet = __commonJS({
863
863
  "use strict";
864
864
  var castPath = require_castPath();
865
865
  var toKey = require_toKey();
866
- function baseGet(object, path2) {
867
- path2 = castPath(path2, object);
868
- var index = 0, length = path2.length;
866
+ function baseGet(object, path3) {
867
+ path3 = castPath(path3, object);
868
+ var index = 0, length = path3.length;
869
869
  while (object != null && index < length) {
870
- object = object[toKey(path2[index++])];
870
+ object = object[toKey(path3[index++])];
871
871
  }
872
872
  return index && index == length ? object : void 0;
873
873
  }
@@ -880,8 +880,8 @@ var require_get = __commonJS({
880
880
  "node_modules/lodash/get.js"(exports2, module2) {
881
881
  "use strict";
882
882
  var baseGet = require_baseGet();
883
- function get2(object, path2, defaultValue) {
884
- var result = object == null ? void 0 : baseGet(object, path2);
883
+ function get2(object, path3, defaultValue) {
884
+ var result = object == null ? void 0 : baseGet(object, path3);
885
885
  return result === void 0 ? defaultValue : result;
886
886
  }
887
887
  module2.exports = get2;
@@ -4984,6 +4984,7 @@ __export(index_exports, {
4984
4984
  Bot: () => Bot,
4985
4985
  BotEnv: () => BotEnv,
4986
4986
  ButtonManager: () => ButtonManager,
4987
+ CacheManager: () => CacheManager,
4987
4988
  ComponentManager: () => ComponentManager,
4988
4989
  DiscordRegex: () => DiscordRegex,
4989
4990
  EmbedManager: () => EmbedManager,
@@ -5546,7 +5547,7 @@ var _BotLog = class _BotLog {
5546
5547
  * Send INFO log - TEXT or EMBED ! Respecte config.log.info
5547
5548
  */
5548
5549
  static async info(content) {
5549
- const logConfig = Bot.config.log;
5550
+ const logConfig = Bot.config?.log;
5550
5551
  if (!logConfig || logConfig.info.console) {
5551
5552
  if (typeof content == "string") {
5552
5553
  Log.info(content);
@@ -5667,7 +5668,7 @@ var EmbedManager = class {
5667
5668
  if (colorC !== "transparent" /* transparent */) {
5668
5669
  embed.setColor(colorC);
5669
5670
  }
5670
- if (Bot.config.botName) {
5671
+ if (Bot.config?.botName) {
5671
5672
  const footer = {
5672
5673
  text: Bot.config.botName
5673
5674
  };
@@ -14326,6 +14327,68 @@ var BotInteraction = class {
14326
14327
  }
14327
14328
  };
14328
14329
 
14330
+ // package.json
14331
+ var package_default = {
14332
+ name: "@spatulox/simplediscordbot",
14333
+ version: "2.1.0",
14334
+ author: "Spatulox",
14335
+ description: "Simple discord bot framework to set up a bot under 30 secondes",
14336
+ exports: {
14337
+ types: "./dist/index.d.ts",
14338
+ import: "./dist/index.js",
14339
+ require: "./dist/index.js"
14340
+ },
14341
+ types: "./dist/index.d.ts",
14342
+ scripts: {
14343
+ "type-check": "tsc --noEmit",
14344
+ build: "npm run type-check && rm -rf ./dist/ && tsup",
14345
+ dev: "npm run type-check && tsx watch src/test/index.ts",
14346
+ patch: "npm run build && npm version patch",
14347
+ minor: "npm run build && npm version minor",
14348
+ major: "npm run build && npm version major",
14349
+ "pub:patch": "npm run patch && npm publish --access public",
14350
+ "pub:minor": "npm run minor && npm publish --access public",
14351
+ "pub:major": "npm run major && npm publish --access public"
14352
+ },
14353
+ license: "MIT",
14354
+ dependencies: {
14355
+ "@spatulox/discord-interaction-manager": "^2.0.6"
14356
+ },
14357
+ peerDependencies: {
14358
+ "discord.js": "^14.26.0"
14359
+ },
14360
+ devDependencies: {
14361
+ "@types/node": "^22.14.0",
14362
+ "@types/node-schedule": "^2.1.7",
14363
+ "discord.js": "^14.26.0",
14364
+ dotenv: "^17.2.4",
14365
+ tsup: "^8.5.1",
14366
+ tsx: "^4.20.3",
14367
+ typescript: "^5.9.3"
14368
+ },
14369
+ keywords: [
14370
+ "discord",
14371
+ "framework",
14372
+ "bot",
14373
+ "client",
14374
+ "discordjs",
14375
+ "discord.js",
14376
+ "node"
14377
+ ],
14378
+ bugs: {
14379
+ url: "https://github.com/Spatulox/SimpleDiscordBot/issues"
14380
+ }
14381
+ };
14382
+
14383
+ // src/SimpleDiscordBotInfo.ts
14384
+ var SimpleDiscordBotInfo = {
14385
+ name: package_default.name,
14386
+ version: package_default.version,
14387
+ author: package_default.author,
14388
+ description: package_default.description,
14389
+ license: package_default.license
14390
+ };
14391
+
14329
14392
  // src/core/Bot.ts
14330
14393
  var _Bot = class _Bot {
14331
14394
  get config() {
@@ -14348,6 +14411,7 @@ var _Bot = class _Bot {
14348
14411
  _Bot._client = client;
14349
14412
  (async () => {
14350
14413
  Log.info(`Using discord.js version: ${import_discord6.version}`);
14414
+ Log.info(`Using simplediscordbot version: ${SimpleDiscordBotInfo.version}`);
14351
14415
  Log.info("Trying to connect to Discord Servers");
14352
14416
  await InternetChecker.checkConnection(3);
14353
14417
  await this.login();
@@ -14420,6 +14484,19 @@ var Bot = _Bot;
14420
14484
  var import_path = __toESM(require("path"));
14421
14485
  var import_promises = __toESM(require("fs/promises"));
14422
14486
  var FileManager = class {
14487
+ /**
14488
+ * Check if a file exist
14489
+ * @param filePath File path with file name
14490
+ * @returns true si le fichier existe, false sinon
14491
+ */
14492
+ static async fileExists(filePath) {
14493
+ try {
14494
+ await import_promises.default.access(filePath);
14495
+ return true;
14496
+ } catch {
14497
+ return false;
14498
+ }
14499
+ }
14423
14500
  /**
14424
14501
  * Reads a JSON file synchronously.
14425
14502
  * @param filePath Full path to the JSON file
@@ -14442,8 +14519,7 @@ var FileManager = class {
14442
14519
  static async listDirectories(directoryPath) {
14443
14520
  try {
14444
14521
  const files = await import_promises.default.readdir(directoryPath, { withFileTypes: true });
14445
- const directories = files.filter((file) => file.isDirectory()).map((dir) => dir.name);
14446
- return directories;
14522
+ return files.filter((file) => file.isDirectory()).map((dir) => dir.name);
14447
14523
  } catch (error) {
14448
14524
  Log.error(`Failed to read directory ${directoryPath}: ${error}`);
14449
14525
  return false;
@@ -14500,16 +14576,7 @@ var FileManager = class {
14500
14576
  return false;
14501
14577
  }
14502
14578
  try {
14503
- const directories = directoryPath.split(import_path.default.sep).filter(Boolean);
14504
- let currentPath = "";
14505
- for (const dir of directories) {
14506
- currentPath = import_path.default.join(currentPath, dir);
14507
- try {
14508
- await import_promises.default.access(currentPath);
14509
- } catch {
14510
- await import_promises.default.mkdir(currentPath, { recursive: true });
14511
- }
14512
- }
14579
+ await import_promises.default.mkdir(directoryPath, { recursive: true });
14513
14580
  if (!filename || filename.trim() === "") {
14514
14581
  Log.error("Cannot write JSON file: empty filename");
14515
14582
  return false;
@@ -14530,12 +14597,207 @@ var FileManager = class {
14530
14597
  return false;
14531
14598
  }
14532
14599
  }
14600
+ /**
14601
+ * Delete a file
14602
+ * @param filePath Full file path
14603
+ * @returns true si supprimé avec succès, false sinon
14604
+ */
14605
+ static async deleteFile(filePath) {
14606
+ try {
14607
+ if (!await this.fileExists(filePath)) {
14608
+ Log.warn(`File does not exist: ${filePath}`);
14609
+ return false;
14610
+ }
14611
+ await import_promises.default.unlink(filePath);
14612
+ Log.info(`Successfully deleted file: ${filePath}`);
14613
+ return true;
14614
+ } catch (error) {
14615
+ Log.error(`Failed to delete file ${filePath}: ${error}`);
14616
+ return false;
14617
+ }
14618
+ }
14619
+ };
14620
+
14621
+ // src/manager/CacheManager.ts
14622
+ var import_path2 = __toESM(require("path"));
14623
+ var CacheManager = class {
14624
+ static get cacheDir() {
14625
+ return import_path2.default.join(process.cwd(), `.${Bot.config?.botName ?? "simplediscordbot"}cache`);
14626
+ }
14627
+ static cleanCacheId(key) {
14628
+ return key.replace(/[^a-zA-Z0-9_-]/g, "_");
14629
+ }
14630
+ static createFilePath(filename) {
14631
+ return import_path2.default.join(this.cacheDir, `${filename}.json`);
14632
+ }
14633
+ /**
14634
+ * New file with cache_id as name
14635
+ * @param cache_id - id which become the cache file name
14636
+ * @param initialData - optional initial data
14637
+ * @returns true if success, false otherwise
14638
+ */
14639
+ static async createCache(cache_id, initialData = {}) {
14640
+ if (!cache_id || typeof cache_id !== "string" || cache_id.trim() === "") {
14641
+ Bot.log.error('"Key" to create a cache must be a non-empty string');
14642
+ return false;
14643
+ }
14644
+ const cleanCacheId = cache_id.replace(/[^a-zA-Z0-9_-]/g, "_");
14645
+ Bot.log.info(`Creating cache file: ${cleanCacheId}.json`);
14646
+ return await FileManager.writeJsonFile(
14647
+ this.cacheDir,
14648
+ this.cleanCacheId(cache_id),
14649
+ initialData,
14650
+ true
14651
+ );
14652
+ }
14653
+ /**
14654
+ * Read cache data or create empty one
14655
+ * @param cache_id
14656
+ * @param default_data default data with default key/value This will be send back if the cache doesn't exist and need to be created
14657
+ * @returns true if success, false otherwise
14658
+ */
14659
+ static async getOrCreateCache(cache_id, default_data) {
14660
+ if (!cache_id || typeof cache_id !== "string" || cache_id.trim() === "") {
14661
+ Log.error('"cache_id" to get or create a cache must be a non-empty string');
14662
+ return false;
14663
+ }
14664
+ const cleanCacheId = this.cleanCacheId(cache_id);
14665
+ const filePath = this.createFilePath(cleanCacheId);
14666
+ if (await FileManager.fileExists(filePath)) {
14667
+ Log.info(`Cache already exists: ${cleanCacheId}.json`);
14668
+ return FileManager.readJsonFile(filePath);
14669
+ }
14670
+ Log.info(`Creating new cache file: ${this.cacheDir}/${cleanCacheId}.json`);
14671
+ const res = await FileManager.writeJsonFile(
14672
+ this.cacheDir,
14673
+ cleanCacheId,
14674
+ default_data,
14675
+ false
14676
+ );
14677
+ return res ? default_data : false;
14678
+ }
14679
+ /**
14680
+ * Read cache data
14681
+ * @param cache_id - cache_id to read
14682
+ * @returns Json data, false otherwise
14683
+ */
14684
+ static async readCache(cache_id) {
14685
+ if (!cache_id || typeof cache_id !== "string") {
14686
+ Bot.log.error('"Key" must be a string');
14687
+ return false;
14688
+ }
14689
+ const cleanCacheId = this.cleanCacheId(cache_id);
14690
+ const filePath = this.createFilePath(cleanCacheId);
14691
+ if (!await FileManager.fileExists(filePath)) {
14692
+ Log.debug(`Cache not found: ${cleanCacheId}.json`);
14693
+ return false;
14694
+ }
14695
+ return await FileManager.readJsonFile(filePath);
14696
+ }
14697
+ /**
14698
+ * Overwrite cache data with the new data
14699
+ * @param cache_id - ID of the cache
14700
+ * @param data - new data
14701
+ * @returns true if success, false otherwise
14702
+ */
14703
+ static async writeCache(cache_id, data) {
14704
+ if (!cache_id || typeof cache_id !== "string") {
14705
+ Log.error("Cache ID must be a string");
14706
+ return false;
14707
+ }
14708
+ const cleanCacheId = this.cleanCacheId(cache_id);
14709
+ Bot.log.info(`Writing to cache: ${cleanCacheId}.json`);
14710
+ return await FileManager.writeJsonFile(
14711
+ this.cacheDir,
14712
+ cleanCacheId,
14713
+ data,
14714
+ true
14715
+ );
14716
+ }
14717
+ /**
14718
+ * Update specific property of the cache
14719
+ * @param cache_id - ID of the cache
14720
+ * @param property - property to update, with key and value
14721
+ * @returns true if success, false otherwise
14722
+ */
14723
+ static async updateCacheProperty(cache_id, property) {
14724
+ const cacheData = await this.readCache(cache_id);
14725
+ if (cacheData === false) {
14726
+ Log.error(`Cache ${cache_id} not found`);
14727
+ return false;
14728
+ }
14729
+ cacheData[property.key] = property.value;
14730
+ return await this.writeCache(cache_id, cacheData);
14731
+ }
14732
+ /**
14733
+ * Reset an entire cache
14734
+ * @param cache_id - cache ID to reset
14735
+ * @returns true if success, false otherwise
14736
+ */
14737
+ static async resetCache(cache_id) {
14738
+ try {
14739
+ const cleanCacheId = cache_id.replace(/[^a-zA-Z0-9_-]/g, "_");
14740
+ await this.writeCache(cache_id, {});
14741
+ Log.info(`Reset cache: ${cleanCacheId}.json`);
14742
+ return true;
14743
+ } catch (error) {
14744
+ Log.error(`Failed to reset cache ${cache_id}: ${error}`);
14745
+ return false;
14746
+ }
14747
+ }
14748
+ /**
14749
+ * Delete an entire cache
14750
+ * @param cache_id - cache ID to delete
14751
+ * @returns true if success, false otherwise
14752
+ */
14753
+ static async deleteCache(cache_id) {
14754
+ try {
14755
+ const cleanCacheId = cache_id.replace(/[^a-zA-Z0-9_-]/g, "_");
14756
+ const filePath = this.createFilePath(cleanCacheId);
14757
+ if (await FileManager.deleteFile(filePath)) {
14758
+ Log.info(`Deleted cache: ${cleanCacheId}.json`);
14759
+ return true;
14760
+ }
14761
+ return false;
14762
+ } catch (error) {
14763
+ Log.error(`Failed to delete cache ${cache_id}: ${error}`);
14764
+ return false;
14765
+ }
14766
+ }
14767
+ /**
14768
+ * List every existing cache
14769
+ * @returns Array of cache_id, false otherwise
14770
+ */
14771
+ static async listCaches() {
14772
+ return await FileManager.listJsonFiles(this.cacheDir);
14773
+ }
14774
+ /**
14775
+ * Clean cache data
14776
+ * @returns true if success, false otherwise
14777
+ */
14778
+ static async clearAllCaches() {
14779
+ try {
14780
+ const caches = await this.listCaches();
14781
+ if (caches === false || caches.length === 0) {
14782
+ return true;
14783
+ }
14784
+ let success = true;
14785
+ for (const cache of caches) {
14786
+ const result = await this.deleteCache(cache.replace(".json", ""));
14787
+ if (!result) success = false;
14788
+ }
14789
+ return success;
14790
+ } catch (error) {
14791
+ Log.error(`Failed to clear caches: ${error}`);
14792
+ return false;
14793
+ }
14794
+ }
14533
14795
  };
14534
14796
 
14535
14797
  // src/manager/messages/WebhookManager.ts
14536
14798
  var import_discord7 = require("discord.js");
14537
14799
  var import_promises2 = require("fs/promises");
14538
- var import_path2 = require("path");
14800
+ var import_path3 = require("path");
14539
14801
  var WebhookManager = class {
14540
14802
  constructor(client, name, avatarPathOrUrl) {
14541
14803
  this.client = client;
@@ -14549,7 +14811,7 @@ var WebhookManager = class {
14549
14811
  return this.avatarPathOrUrl;
14550
14812
  }
14551
14813
  try {
14552
- const resolvedPath = (0, import_path2.resolve)(process.cwd(), this.avatarPathOrUrl);
14814
+ const resolvedPath = (0, import_path3.resolve)(process.cwd(), this.avatarPathOrUrl);
14553
14815
  return await (0, import_promises2.readFile)(resolvedPath);
14554
14816
  } catch (error) {
14555
14817
  Bot.log.warn(`Failed to load avatar from ${this.avatarPathOrUrl}: ${error}`);
@@ -16148,73 +16410,12 @@ var SimpleMutex = class {
16148
16410
  return this._locked;
16149
16411
  }
16150
16412
  };
16151
-
16152
- // package.json
16153
- var package_default = {
16154
- name: "@spatulox/simplediscordbot",
16155
- version: "2.0.2",
16156
- author: "Spatulox",
16157
- description: "Simple discord bot framework to set up a bot under 30 secondes",
16158
- exports: {
16159
- types: "./dist/index.d.ts",
16160
- import: "./dist/index.js",
16161
- require: "./dist/index.js"
16162
- },
16163
- types: "./dist/index.d.ts",
16164
- scripts: {
16165
- "type-check": "tsc --noEmit",
16166
- build: "npm run type-check && rm -rf ./dist/ && tsup",
16167
- dev: "npm run type-check && tsx watch src/test/index.ts",
16168
- patch: "npm run build && npm version patch",
16169
- minor: "npm run build && npm version minor",
16170
- major: "npm run build && npm version major",
16171
- "pub:patch": "npm run patch && npm publish --access public",
16172
- "pub:minor": "npm run minor && npm publish --access public",
16173
- "pub:major": "npm run major && npm publish --access public"
16174
- },
16175
- license: "MIT",
16176
- dependencies: {
16177
- "@spatulox/discord-interaction-manager": "^2.0.6"
16178
- },
16179
- peerDependencies: {
16180
- "discord.js": "^14.26.0"
16181
- },
16182
- devDependencies: {
16183
- "@types/node": "^22.14.0",
16184
- "@types/node-schedule": "^2.1.7",
16185
- "discord.js": "^14.26.0",
16186
- dotenv: "^17.2.4",
16187
- tsup: "^8.5.1",
16188
- tsx: "^4.20.3",
16189
- typescript: "^5.9.3"
16190
- },
16191
- keywords: [
16192
- "discord",
16193
- "framework",
16194
- "bot",
16195
- "client",
16196
- "discordjs",
16197
- "discord.js",
16198
- "node"
16199
- ],
16200
- bugs: {
16201
- url: "https://github.com/Spatulox/SimpleDiscordBot/issues"
16202
- }
16203
- };
16204
-
16205
- // src/SimpleDiscordBotInfo.ts
16206
- var SimpleDiscordBotInfo = {
16207
- name: package_default.name,
16208
- version: package_default.license,
16209
- author: package_default.author,
16210
- description: package_default.description,
16211
- license: package_default.license
16212
- };
16213
16413
  // Annotate the CommonJS export names for ESM import in node:
16214
16414
  0 && (module.exports = {
16215
16415
  Bot,
16216
16416
  BotEnv,
16217
16417
  ButtonManager,
16418
+ CacheManager,
16218
16419
  ComponentManager,
16219
16420
  DiscordRegex,
16220
16421
  EmbedManager,
package/dist/index.mjs CHANGED
@@ -857,11 +857,11 @@ var require_baseGet = __commonJS({
857
857
  "use strict";
858
858
  var castPath = require_castPath();
859
859
  var toKey = require_toKey();
860
- function baseGet(object, path2) {
861
- path2 = castPath(path2, object);
862
- var index = 0, length = path2.length;
860
+ function baseGet(object, path3) {
861
+ path3 = castPath(path3, object);
862
+ var index = 0, length = path3.length;
863
863
  while (object != null && index < length) {
864
- object = object[toKey(path2[index++])];
864
+ object = object[toKey(path3[index++])];
865
865
  }
866
866
  return index && index == length ? object : void 0;
867
867
  }
@@ -874,8 +874,8 @@ var require_get = __commonJS({
874
874
  "node_modules/lodash/get.js"(exports, module) {
875
875
  "use strict";
876
876
  var baseGet = require_baseGet();
877
- function get2(object, path2, defaultValue) {
878
- var result = object == null ? void 0 : baseGet(object, path2);
877
+ function get2(object, path3, defaultValue) {
878
+ var result = object == null ? void 0 : baseGet(object, path3);
879
879
  return result === void 0 ? defaultValue : result;
880
880
  }
881
881
  module.exports = get2;
@@ -5529,7 +5529,7 @@ var _BotLog = class _BotLog {
5529
5529
  * Send INFO log - TEXT or EMBED ! Respecte config.log.info
5530
5530
  */
5531
5531
  static async info(content) {
5532
- const logConfig = Bot.config.log;
5532
+ const logConfig = Bot.config?.log;
5533
5533
  if (!logConfig || logConfig.info.console) {
5534
5534
  if (typeof content == "string") {
5535
5535
  Log.info(content);
@@ -5653,7 +5653,7 @@ var EmbedManager = class {
5653
5653
  if (colorC !== "transparent" /* transparent */) {
5654
5654
  embed.setColor(colorC);
5655
5655
  }
5656
- if (Bot.config.botName) {
5656
+ if (Bot.config?.botName) {
5657
5657
  const footer = {
5658
5658
  text: Bot.config.botName
5659
5659
  };
@@ -14320,6 +14320,68 @@ var BotInteraction = class {
14320
14320
  }
14321
14321
  };
14322
14322
 
14323
+ // package.json
14324
+ var package_default = {
14325
+ name: "@spatulox/simplediscordbot",
14326
+ version: "2.1.0",
14327
+ author: "Spatulox",
14328
+ description: "Simple discord bot framework to set up a bot under 30 secondes",
14329
+ exports: {
14330
+ types: "./dist/index.d.ts",
14331
+ import: "./dist/index.js",
14332
+ require: "./dist/index.js"
14333
+ },
14334
+ types: "./dist/index.d.ts",
14335
+ scripts: {
14336
+ "type-check": "tsc --noEmit",
14337
+ build: "npm run type-check && rm -rf ./dist/ && tsup",
14338
+ dev: "npm run type-check && tsx watch src/test/index.ts",
14339
+ patch: "npm run build && npm version patch",
14340
+ minor: "npm run build && npm version minor",
14341
+ major: "npm run build && npm version major",
14342
+ "pub:patch": "npm run patch && npm publish --access public",
14343
+ "pub:minor": "npm run minor && npm publish --access public",
14344
+ "pub:major": "npm run major && npm publish --access public"
14345
+ },
14346
+ license: "MIT",
14347
+ dependencies: {
14348
+ "@spatulox/discord-interaction-manager": "^2.0.6"
14349
+ },
14350
+ peerDependencies: {
14351
+ "discord.js": "^14.26.0"
14352
+ },
14353
+ devDependencies: {
14354
+ "@types/node": "^22.14.0",
14355
+ "@types/node-schedule": "^2.1.7",
14356
+ "discord.js": "^14.26.0",
14357
+ dotenv: "^17.2.4",
14358
+ tsup: "^8.5.1",
14359
+ tsx: "^4.20.3",
14360
+ typescript: "^5.9.3"
14361
+ },
14362
+ keywords: [
14363
+ "discord",
14364
+ "framework",
14365
+ "bot",
14366
+ "client",
14367
+ "discordjs",
14368
+ "discord.js",
14369
+ "node"
14370
+ ],
14371
+ bugs: {
14372
+ url: "https://github.com/Spatulox/SimpleDiscordBot/issues"
14373
+ }
14374
+ };
14375
+
14376
+ // src/SimpleDiscordBotInfo.ts
14377
+ var SimpleDiscordBotInfo = {
14378
+ name: package_default.name,
14379
+ version: package_default.version,
14380
+ author: package_default.author,
14381
+ description: package_default.description,
14382
+ license: package_default.license
14383
+ };
14384
+
14323
14385
  // src/core/Bot.ts
14324
14386
  var _Bot = class _Bot {
14325
14387
  get config() {
@@ -14342,6 +14404,7 @@ var _Bot = class _Bot {
14342
14404
  _Bot._client = client;
14343
14405
  (async () => {
14344
14406
  Log.info(`Using discord.js version: ${version}`);
14407
+ Log.info(`Using simplediscordbot version: ${SimpleDiscordBotInfo.version}`);
14345
14408
  Log.info("Trying to connect to Discord Servers");
14346
14409
  await InternetChecker.checkConnection(3);
14347
14410
  await this.login();
@@ -14414,6 +14477,19 @@ var Bot = _Bot;
14414
14477
  import path from "path";
14415
14478
  import fs from "fs/promises";
14416
14479
  var FileManager = class {
14480
+ /**
14481
+ * Check if a file exist
14482
+ * @param filePath File path with file name
14483
+ * @returns true si le fichier existe, false sinon
14484
+ */
14485
+ static async fileExists(filePath) {
14486
+ try {
14487
+ await fs.access(filePath);
14488
+ return true;
14489
+ } catch {
14490
+ return false;
14491
+ }
14492
+ }
14417
14493
  /**
14418
14494
  * Reads a JSON file synchronously.
14419
14495
  * @param filePath Full path to the JSON file
@@ -14436,8 +14512,7 @@ var FileManager = class {
14436
14512
  static async listDirectories(directoryPath) {
14437
14513
  try {
14438
14514
  const files = await fs.readdir(directoryPath, { withFileTypes: true });
14439
- const directories = files.filter((file) => file.isDirectory()).map((dir) => dir.name);
14440
- return directories;
14515
+ return files.filter((file) => file.isDirectory()).map((dir) => dir.name);
14441
14516
  } catch (error) {
14442
14517
  Log.error(`Failed to read directory ${directoryPath}: ${error}`);
14443
14518
  return false;
@@ -14494,16 +14569,7 @@ var FileManager = class {
14494
14569
  return false;
14495
14570
  }
14496
14571
  try {
14497
- const directories = directoryPath.split(path.sep).filter(Boolean);
14498
- let currentPath = "";
14499
- for (const dir of directories) {
14500
- currentPath = path.join(currentPath, dir);
14501
- try {
14502
- await fs.access(currentPath);
14503
- } catch {
14504
- await fs.mkdir(currentPath, { recursive: true });
14505
- }
14506
- }
14572
+ await fs.mkdir(directoryPath, { recursive: true });
14507
14573
  if (!filename || filename.trim() === "") {
14508
14574
  Log.error("Cannot write JSON file: empty filename");
14509
14575
  return false;
@@ -14524,6 +14590,201 @@ var FileManager = class {
14524
14590
  return false;
14525
14591
  }
14526
14592
  }
14593
+ /**
14594
+ * Delete a file
14595
+ * @param filePath Full file path
14596
+ * @returns true si supprimé avec succès, false sinon
14597
+ */
14598
+ static async deleteFile(filePath) {
14599
+ try {
14600
+ if (!await this.fileExists(filePath)) {
14601
+ Log.warn(`File does not exist: ${filePath}`);
14602
+ return false;
14603
+ }
14604
+ await fs.unlink(filePath);
14605
+ Log.info(`Successfully deleted file: ${filePath}`);
14606
+ return true;
14607
+ } catch (error) {
14608
+ Log.error(`Failed to delete file ${filePath}: ${error}`);
14609
+ return false;
14610
+ }
14611
+ }
14612
+ };
14613
+
14614
+ // src/manager/CacheManager.ts
14615
+ import path2 from "path";
14616
+ var CacheManager = class {
14617
+ static get cacheDir() {
14618
+ return path2.join(process.cwd(), `.${Bot.config?.botName ?? "simplediscordbot"}cache`);
14619
+ }
14620
+ static cleanCacheId(key) {
14621
+ return key.replace(/[^a-zA-Z0-9_-]/g, "_");
14622
+ }
14623
+ static createFilePath(filename) {
14624
+ return path2.join(this.cacheDir, `${filename}.json`);
14625
+ }
14626
+ /**
14627
+ * New file with cache_id as name
14628
+ * @param cache_id - id which become the cache file name
14629
+ * @param initialData - optional initial data
14630
+ * @returns true if success, false otherwise
14631
+ */
14632
+ static async createCache(cache_id, initialData = {}) {
14633
+ if (!cache_id || typeof cache_id !== "string" || cache_id.trim() === "") {
14634
+ Bot.log.error('"Key" to create a cache must be a non-empty string');
14635
+ return false;
14636
+ }
14637
+ const cleanCacheId = cache_id.replace(/[^a-zA-Z0-9_-]/g, "_");
14638
+ Bot.log.info(`Creating cache file: ${cleanCacheId}.json`);
14639
+ return await FileManager.writeJsonFile(
14640
+ this.cacheDir,
14641
+ this.cleanCacheId(cache_id),
14642
+ initialData,
14643
+ true
14644
+ );
14645
+ }
14646
+ /**
14647
+ * Read cache data or create empty one
14648
+ * @param cache_id
14649
+ * @param default_data default data with default key/value This will be send back if the cache doesn't exist and need to be created
14650
+ * @returns true if success, false otherwise
14651
+ */
14652
+ static async getOrCreateCache(cache_id, default_data) {
14653
+ if (!cache_id || typeof cache_id !== "string" || cache_id.trim() === "") {
14654
+ Log.error('"cache_id" to get or create a cache must be a non-empty string');
14655
+ return false;
14656
+ }
14657
+ const cleanCacheId = this.cleanCacheId(cache_id);
14658
+ const filePath = this.createFilePath(cleanCacheId);
14659
+ if (await FileManager.fileExists(filePath)) {
14660
+ Log.info(`Cache already exists: ${cleanCacheId}.json`);
14661
+ return FileManager.readJsonFile(filePath);
14662
+ }
14663
+ Log.info(`Creating new cache file: ${this.cacheDir}/${cleanCacheId}.json`);
14664
+ const res = await FileManager.writeJsonFile(
14665
+ this.cacheDir,
14666
+ cleanCacheId,
14667
+ default_data,
14668
+ false
14669
+ );
14670
+ return res ? default_data : false;
14671
+ }
14672
+ /**
14673
+ * Read cache data
14674
+ * @param cache_id - cache_id to read
14675
+ * @returns Json data, false otherwise
14676
+ */
14677
+ static async readCache(cache_id) {
14678
+ if (!cache_id || typeof cache_id !== "string") {
14679
+ Bot.log.error('"Key" must be a string');
14680
+ return false;
14681
+ }
14682
+ const cleanCacheId = this.cleanCacheId(cache_id);
14683
+ const filePath = this.createFilePath(cleanCacheId);
14684
+ if (!await FileManager.fileExists(filePath)) {
14685
+ Log.debug(`Cache not found: ${cleanCacheId}.json`);
14686
+ return false;
14687
+ }
14688
+ return await FileManager.readJsonFile(filePath);
14689
+ }
14690
+ /**
14691
+ * Overwrite cache data with the new data
14692
+ * @param cache_id - ID of the cache
14693
+ * @param data - new data
14694
+ * @returns true if success, false otherwise
14695
+ */
14696
+ static async writeCache(cache_id, data) {
14697
+ if (!cache_id || typeof cache_id !== "string") {
14698
+ Log.error("Cache ID must be a string");
14699
+ return false;
14700
+ }
14701
+ const cleanCacheId = this.cleanCacheId(cache_id);
14702
+ Bot.log.info(`Writing to cache: ${cleanCacheId}.json`);
14703
+ return await FileManager.writeJsonFile(
14704
+ this.cacheDir,
14705
+ cleanCacheId,
14706
+ data,
14707
+ true
14708
+ );
14709
+ }
14710
+ /**
14711
+ * Update specific property of the cache
14712
+ * @param cache_id - ID of the cache
14713
+ * @param property - property to update, with key and value
14714
+ * @returns true if success, false otherwise
14715
+ */
14716
+ static async updateCacheProperty(cache_id, property) {
14717
+ const cacheData = await this.readCache(cache_id);
14718
+ if (cacheData === false) {
14719
+ Log.error(`Cache ${cache_id} not found`);
14720
+ return false;
14721
+ }
14722
+ cacheData[property.key] = property.value;
14723
+ return await this.writeCache(cache_id, cacheData);
14724
+ }
14725
+ /**
14726
+ * Reset an entire cache
14727
+ * @param cache_id - cache ID to reset
14728
+ * @returns true if success, false otherwise
14729
+ */
14730
+ static async resetCache(cache_id) {
14731
+ try {
14732
+ const cleanCacheId = cache_id.replace(/[^a-zA-Z0-9_-]/g, "_");
14733
+ await this.writeCache(cache_id, {});
14734
+ Log.info(`Reset cache: ${cleanCacheId}.json`);
14735
+ return true;
14736
+ } catch (error) {
14737
+ Log.error(`Failed to reset cache ${cache_id}: ${error}`);
14738
+ return false;
14739
+ }
14740
+ }
14741
+ /**
14742
+ * Delete an entire cache
14743
+ * @param cache_id - cache ID to delete
14744
+ * @returns true if success, false otherwise
14745
+ */
14746
+ static async deleteCache(cache_id) {
14747
+ try {
14748
+ const cleanCacheId = cache_id.replace(/[^a-zA-Z0-9_-]/g, "_");
14749
+ const filePath = this.createFilePath(cleanCacheId);
14750
+ if (await FileManager.deleteFile(filePath)) {
14751
+ Log.info(`Deleted cache: ${cleanCacheId}.json`);
14752
+ return true;
14753
+ }
14754
+ return false;
14755
+ } catch (error) {
14756
+ Log.error(`Failed to delete cache ${cache_id}: ${error}`);
14757
+ return false;
14758
+ }
14759
+ }
14760
+ /**
14761
+ * List every existing cache
14762
+ * @returns Array of cache_id, false otherwise
14763
+ */
14764
+ static async listCaches() {
14765
+ return await FileManager.listJsonFiles(this.cacheDir);
14766
+ }
14767
+ /**
14768
+ * Clean cache data
14769
+ * @returns true if success, false otherwise
14770
+ */
14771
+ static async clearAllCaches() {
14772
+ try {
14773
+ const caches = await this.listCaches();
14774
+ if (caches === false || caches.length === 0) {
14775
+ return true;
14776
+ }
14777
+ let success = true;
14778
+ for (const cache of caches) {
14779
+ const result = await this.deleteCache(cache.replace(".json", ""));
14780
+ if (!result) success = false;
14781
+ }
14782
+ return success;
14783
+ } catch (error) {
14784
+ Log.error(`Failed to clear caches: ${error}`);
14785
+ return false;
14786
+ }
14787
+ }
14527
14788
  };
14528
14789
 
14529
14790
  // src/manager/messages/WebhookManager.ts
@@ -16170,72 +16431,11 @@ var SimpleMutex = class {
16170
16431
  return this._locked;
16171
16432
  }
16172
16433
  };
16173
-
16174
- // package.json
16175
- var package_default = {
16176
- name: "@spatulox/simplediscordbot",
16177
- version: "2.0.2",
16178
- author: "Spatulox",
16179
- description: "Simple discord bot framework to set up a bot under 30 secondes",
16180
- exports: {
16181
- types: "./dist/index.d.ts",
16182
- import: "./dist/index.js",
16183
- require: "./dist/index.js"
16184
- },
16185
- types: "./dist/index.d.ts",
16186
- scripts: {
16187
- "type-check": "tsc --noEmit",
16188
- build: "npm run type-check && rm -rf ./dist/ && tsup",
16189
- dev: "npm run type-check && tsx watch src/test/index.ts",
16190
- patch: "npm run build && npm version patch",
16191
- minor: "npm run build && npm version minor",
16192
- major: "npm run build && npm version major",
16193
- "pub:patch": "npm run patch && npm publish --access public",
16194
- "pub:minor": "npm run minor && npm publish --access public",
16195
- "pub:major": "npm run major && npm publish --access public"
16196
- },
16197
- license: "MIT",
16198
- dependencies: {
16199
- "@spatulox/discord-interaction-manager": "^2.0.6"
16200
- },
16201
- peerDependencies: {
16202
- "discord.js": "^14.26.0"
16203
- },
16204
- devDependencies: {
16205
- "@types/node": "^22.14.0",
16206
- "@types/node-schedule": "^2.1.7",
16207
- "discord.js": "^14.26.0",
16208
- dotenv: "^17.2.4",
16209
- tsup: "^8.5.1",
16210
- tsx: "^4.20.3",
16211
- typescript: "^5.9.3"
16212
- },
16213
- keywords: [
16214
- "discord",
16215
- "framework",
16216
- "bot",
16217
- "client",
16218
- "discordjs",
16219
- "discord.js",
16220
- "node"
16221
- ],
16222
- bugs: {
16223
- url: "https://github.com/Spatulox/SimpleDiscordBot/issues"
16224
- }
16225
- };
16226
-
16227
- // src/SimpleDiscordBotInfo.ts
16228
- var SimpleDiscordBotInfo = {
16229
- name: package_default.name,
16230
- version: package_default.license,
16231
- author: package_default.author,
16232
- description: package_default.description,
16233
- license: package_default.license
16234
- };
16235
16434
  export {
16236
16435
  Bot,
16237
16436
  BotEnv,
16238
16437
  ButtonManager,
16438
+ CacheManager,
16239
16439
  ComponentManager,
16240
16440
  DiscordRegex,
16241
16441
  EmbedManager,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spatulox/simplediscordbot",
3
- "version": "2.0.3",
3
+ "version": "2.1.1",
4
4
  "author": "Spatulox",
5
5
  "description": "Simple discord bot framework to set up a bot under 30 secondes",
6
6
  "exports": {