@feizk/logger 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,70 +21,27 @@ logger.error('This is an error');
21
21
  logger.debug('This is a debug message');
22
22
  ```
23
23
 
24
- ### Options
24
+ ## Options
25
25
 
26
- Customize the logger with constructor options:
26
+ | Option | Type | Default | Description |
27
+ | --------------- | -------------------------------- | ----------- | ------------------------------------- |
28
+ | `enableColors` | `boolean` | `true` | Enable colored output |
29
+ | `formatTimestamp`| `function \| undefined` | `ISO format`| Custom timestamp formatter function |
30
+ | `formatLog` | `function \| undefined` | `undefined` | Custom log formatter function |
31
+ | `level` | `'debug' \| 'info' \| 'warn' \| 'error'` | `'debug'` | Minimum log level |
32
+ | `discord` | `object \| undefined` | `undefined` | Discord transport options |
27
33
 
28
- ```typescript
29
- const logger = new Logger({
30
- enableColors: true, // Default: true
31
- formatTimestamp: undefined, // Custom timestamp formatter function, Default: ISO format
32
- formatLog: undefined, // Custom log formatter function, Default: undefined
33
- level: 'debug', // 'debug' | 'info' | 'warn' | 'error', Default: 'debug'
34
- discord: {
35
- enable: false, // Enable Discord transport
36
- webhookURL: '', // Discord webhook URL
37
- formatEmbed: undefined, // Custom embed formatter function
38
- },
39
- });
40
- ```
34
+ ### Discord Options
41
35
 
42
- #### Examples
36
+ The `discord` option configures Discord webhook integration. It has the following properties:
43
37
 
44
- ```typescript
45
- // Disable colors
46
- const noColorLogger = new Logger({ enableColors: false });
47
-
48
- // Use locale timestamp
49
- const localeLogger = new Logger({
50
- formatTimestamp: (types) => [types.Locale, new Date().toLocaleString()],
51
- });
52
-
53
- // Custom timestamp
54
- const customLogger = new Logger({
55
- formatTimestamp: () => [TIMESTAMP_TYPES.Custom, 'custom-time'],
56
- });
57
-
58
- // Filter logs below info level
59
- const infoLogger = new Logger({ level: 'info' });
60
- infoLogger.debug('Not logged');
61
- infoLogger.info('Logged'); // and higher
62
-
63
- // Change level dynamically
64
- logger.setLevel('error');
65
-
66
- // Enable Discord transport
67
- const discordLogger = new Logger({
68
- discord: {
69
- enable: true,
70
- webhookURL: 'https://discord.com/api/webhooks/123456789/abcdef',
71
- },
72
- });
73
- discordLogger.error('This will be sent to Discord');
74
-
75
- // Custom embed formatting
76
- const customDiscordLogger = new Logger({
77
- discord: {
78
- enable: true,
79
- webhookURL: 'https://discord.com/api/webhooks/123456789/abcdef',
80
- formatEmbed: (level, timestamp, message) => ({
81
- title: `${level} - Custom`,
82
- description: `**Timestamp:** ${timestamp}\n**Message:** ${message}`,
83
- color: 0xff0000, // Red
84
- }),
85
- },
86
- });
87
- ```
38
+ - `enable`: `boolean`, default `false` - Enable Discord transport
39
+ - `webhookURL`: `string`, default `''` - Discord webhook URL
40
+ - `formatEmbed`: `function \| undefined`, default `undefined` - Custom embed formatter function
41
+ - `batchSize`: `number`, default `10` - Number of embeds per batch request
42
+ - `batchDelay`: `number`, default `2000` - Delay in ms between batch sends
43
+ - `maxRetries`: `number`, default `3` - Maximum retry attempts for failed sends
44
+ - `retryDelayBase`: `number`, default `1000` - Base delay in ms for exponential backoff
88
45
 
89
46
  ## API
90
47
 
@@ -97,3 +54,7 @@ const customDiscordLogger = new Logger({
97
54
  - `setLevel(level: LogLevel)`: Sets the minimum log level for filtering messages.
98
55
 
99
56
  All messages include a timestamp and are colored accordingly (unless disabled via options).
57
+
58
+ ## License
59
+
60
+ MIT
package/dist/index.d.mts CHANGED
@@ -8,14 +8,18 @@ interface TimestampTypes {
8
8
  interface DiscordOptions {
9
9
  enable: boolean;
10
10
  webhookURL: string;
11
+ batchSize?: number;
12
+ batchDelay?: number;
13
+ maxRetries?: number;
14
+ retryDelayBase?: number;
11
15
  formatEmbed?: (level: LogLevel, timestamp: string, message: string) => Record<string, unknown>;
12
16
  }
13
17
  interface LoggerOptions {
18
+ level?: LogLevel;
14
19
  enableColors?: boolean;
20
+ discord?: DiscordOptions;
15
21
  formatTimestamp?: (types: TimestampTypes, date?: Date) => [TimestampType, string];
16
22
  formatLog?: (level: string, timestamp: string, args: unknown[]) => string;
17
- level?: LogLevel;
18
- discord?: DiscordOptions;
19
23
  }
20
24
 
21
25
  /**
@@ -24,6 +28,9 @@ interface LoggerOptions {
24
28
  declare class Logger {
25
29
  private options;
26
30
  private level;
31
+ private discordQueue;
32
+ private isProcessing;
33
+ private processTimeout?;
27
34
  constructor(options?: LoggerOptions);
28
35
  /**
29
36
  * Sets the minimum log level for filtering messages.
@@ -37,6 +44,15 @@ declare class Logger {
37
44
  * @param args - The log arguments.
38
45
  */
39
46
  private sendToDiscord;
47
+ /**
48
+ * Processes the Discord queue by sending batches of embeds.
49
+ */
50
+ private processQueue;
51
+ /**
52
+ * Sends a batch of embeds to Discord.
53
+ * @param embeds - The embeds to send.
54
+ */
55
+ private sendBatch;
40
56
  /**
41
57
  * Checks if a log level should be output based on the current log level.
42
58
  * @param level - The log level to check.
package/dist/index.d.ts CHANGED
@@ -8,14 +8,18 @@ interface TimestampTypes {
8
8
  interface DiscordOptions {
9
9
  enable: boolean;
10
10
  webhookURL: string;
11
+ batchSize?: number;
12
+ batchDelay?: number;
13
+ maxRetries?: number;
14
+ retryDelayBase?: number;
11
15
  formatEmbed?: (level: LogLevel, timestamp: string, message: string) => Record<string, unknown>;
12
16
  }
13
17
  interface LoggerOptions {
18
+ level?: LogLevel;
14
19
  enableColors?: boolean;
20
+ discord?: DiscordOptions;
15
21
  formatTimestamp?: (types: TimestampTypes, date?: Date) => [TimestampType, string];
16
22
  formatLog?: (level: string, timestamp: string, args: unknown[]) => string;
17
- level?: LogLevel;
18
- discord?: DiscordOptions;
19
23
  }
20
24
 
21
25
  /**
@@ -24,6 +28,9 @@ interface LoggerOptions {
24
28
  declare class Logger {
25
29
  private options;
26
30
  private level;
31
+ private discordQueue;
32
+ private isProcessing;
33
+ private processTimeout?;
27
34
  constructor(options?: LoggerOptions);
28
35
  /**
29
36
  * Sets the minimum log level for filtering messages.
@@ -37,6 +44,15 @@ declare class Logger {
37
44
  * @param args - The log arguments.
38
45
  */
39
46
  private sendToDiscord;
47
+ /**
48
+ * Processes the Discord queue by sending batches of embeds.
49
+ */
50
+ private processQueue;
51
+ /**
52
+ * Sends a batch of embeds to Discord.
53
+ * @param embeds - The embeds to send.
54
+ */
55
+ private sendBatch;
40
56
  /**
41
57
  * Checks if a log level should be output based on the current log level.
42
58
  * @param level - The log level to check.
package/dist/index.js CHANGED
@@ -87,6 +87,8 @@ var LOG_LEVEL_PRIORITIES = {
87
87
  };
88
88
  var Logger = class {
89
89
  constructor(options = {}) {
90
+ this.discordQueue = [];
91
+ this.isProcessing = false;
90
92
  this.options = {
91
93
  enableColors: options.enableColors ?? true,
92
94
  formatTimestamp: options.formatTimestamp ?? defaultFormatTimestamp,
@@ -108,7 +110,7 @@ var Logger = class {
108
110
  * @param timestamp - The formatted timestamp.
109
111
  * @param args - The log arguments.
110
112
  */
111
- async sendToDiscord(level, timestamp, args) {
113
+ sendToDiscord(level, timestamp, args) {
112
114
  const discord = this.options.discord;
113
115
  if (!discord?.enable) return;
114
116
  try {
@@ -124,11 +126,49 @@ var Logger = class {
124
126
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
125
127
  color: getDiscordColor(level)
126
128
  };
129
+ this.discordQueue.push({ embed, retryCount: 0 });
130
+ if (!this.isProcessing) {
131
+ this.isProcessing = true;
132
+ setTimeout(() => this.processQueue(), 0);
133
+ }
134
+ }
135
+ /**
136
+ * Processes the Discord queue by sending batches of embeds.
137
+ */
138
+ processQueue() {
139
+ if (this.discordQueue.length === 0) {
140
+ this.isProcessing = false;
141
+ return;
142
+ }
143
+ this.isProcessing = true;
144
+ const discord = this.options.discord;
145
+ const batchSize = discord.batchSize ?? 10;
146
+ const batch = this.discordQueue.splice(0, batchSize);
147
+ this.sendBatch(batch.map((item) => item.embed)).then(() => {
148
+ const delay = discord.batchDelay ?? 2e3;
149
+ this.processTimeout = setTimeout(() => this.processQueue(), delay);
150
+ }).catch(() => {
151
+ const maxRetries = discord.maxRetries ?? 3;
152
+ const retryItems = batch.filter((item) => item.retryCount < maxRetries).map((item) => ({
153
+ ...item,
154
+ retryCount: item.retryCount + 1
155
+ }));
156
+ this.discordQueue.unshift(...retryItems);
157
+ const retryDelayBase = discord.retryDelayBase ?? 1e3;
158
+ const delay = retryDelayBase * Math.pow(2, batch[0]?.retryCount ?? 0);
159
+ this.processTimeout = setTimeout(() => this.processQueue(), delay);
160
+ });
161
+ }
162
+ /**
163
+ * Sends a batch of embeds to Discord.
164
+ * @param embeds - The embeds to send.
165
+ */
166
+ async sendBatch(embeds) {
167
+ const discord = this.options.discord;
127
168
  await fetch(discord.webhookURL, {
128
169
  method: "POST",
129
170
  headers: { "Content-Type": "application/json" },
130
- body: JSON.stringify({ embeds: [embed] })
131
- }).catch(() => {
171
+ body: JSON.stringify({ embeds })
132
172
  });
133
173
  }
134
174
  /**
@@ -197,4 +237,3 @@ var Logger = class {
197
237
  Logger,
198
238
  TIMESTAMP_TYPES
199
239
  });
200
- //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -50,6 +50,8 @@ var LOG_LEVEL_PRIORITIES = {
50
50
  };
51
51
  var Logger = class {
52
52
  constructor(options = {}) {
53
+ this.discordQueue = [];
54
+ this.isProcessing = false;
53
55
  this.options = {
54
56
  enableColors: options.enableColors ?? true,
55
57
  formatTimestamp: options.formatTimestamp ?? defaultFormatTimestamp,
@@ -71,7 +73,7 @@ var Logger = class {
71
73
  * @param timestamp - The formatted timestamp.
72
74
  * @param args - The log arguments.
73
75
  */
74
- async sendToDiscord(level, timestamp, args) {
76
+ sendToDiscord(level, timestamp, args) {
75
77
  const discord = this.options.discord;
76
78
  if (!discord?.enable) return;
77
79
  try {
@@ -87,11 +89,49 @@ var Logger = class {
87
89
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
88
90
  color: getDiscordColor(level)
89
91
  };
92
+ this.discordQueue.push({ embed, retryCount: 0 });
93
+ if (!this.isProcessing) {
94
+ this.isProcessing = true;
95
+ setTimeout(() => this.processQueue(), 0);
96
+ }
97
+ }
98
+ /**
99
+ * Processes the Discord queue by sending batches of embeds.
100
+ */
101
+ processQueue() {
102
+ if (this.discordQueue.length === 0) {
103
+ this.isProcessing = false;
104
+ return;
105
+ }
106
+ this.isProcessing = true;
107
+ const discord = this.options.discord;
108
+ const batchSize = discord.batchSize ?? 10;
109
+ const batch = this.discordQueue.splice(0, batchSize);
110
+ this.sendBatch(batch.map((item) => item.embed)).then(() => {
111
+ const delay = discord.batchDelay ?? 2e3;
112
+ this.processTimeout = setTimeout(() => this.processQueue(), delay);
113
+ }).catch(() => {
114
+ const maxRetries = discord.maxRetries ?? 3;
115
+ const retryItems = batch.filter((item) => item.retryCount < maxRetries).map((item) => ({
116
+ ...item,
117
+ retryCount: item.retryCount + 1
118
+ }));
119
+ this.discordQueue.unshift(...retryItems);
120
+ const retryDelayBase = discord.retryDelayBase ?? 1e3;
121
+ const delay = retryDelayBase * Math.pow(2, batch[0]?.retryCount ?? 0);
122
+ this.processTimeout = setTimeout(() => this.processQueue(), delay);
123
+ });
124
+ }
125
+ /**
126
+ * Sends a batch of embeds to Discord.
127
+ * @param embeds - The embeds to send.
128
+ */
129
+ async sendBatch(embeds) {
130
+ const discord = this.options.discord;
90
131
  await fetch(discord.webhookURL, {
91
132
  method: "POST",
92
133
  headers: { "Content-Type": "application/json" },
93
- body: JSON.stringify({ embeds: [embed] })
94
- }).catch(() => {
134
+ body: JSON.stringify({ embeds })
95
135
  });
96
136
  }
97
137
  /**
@@ -159,4 +199,3 @@ export {
159
199
  Logger,
160
200
  TIMESTAMP_TYPES
161
201
  };
162
- //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feizk/logger",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "A simple logger package with colored outputs and timestamps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/logger.ts"],"sourcesContent":["export { Logger } from './logger';\nexport { TIMESTAMP_TYPES } from './utils';\nexport type {\n LoggerOptions,\n LogLevel,\n TimestampTypes,\n TimestampType,\n DiscordOptions,\n} from './types';\n","import chalk from 'chalk';\nimport type { LoggerOptions, TimestampTypes, LogLevel } from './types';\n\nexport const TIMESTAMP_TYPES: TimestampTypes = {\n ISO: 'iso',\n Locale: 'locale',\n Custom: 'custom',\n};\n\nexport function formatTimestamp(\n formatTimestampFn: NonNullable<LoggerOptions['formatTimestamp']>,\n types: TimestampTypes,\n date: Date = new Date(),\n): string {\n const [, timestamp] = formatTimestampFn(types, date);\n return timestamp;\n}\n\nexport function getColor(level: string, enableColors: boolean): string {\n if (!enableColors) return level;\n const colors: Record<string, string> = {\n '[INFO]': chalk.blue(level),\n '[WARN]': chalk.yellow(level),\n '[ERROR]': chalk.red(level),\n '[DEBUG]': chalk.gray(level),\n };\n return colors[level] || level;\n}\n\nexport function getDiscordColor(level: LogLevel): number {\n const colors: Record<LogLevel, number> = {\n debug: 0x95a5a6,\n info: 0x3498db,\n warn: 0xf39c12,\n error: 0xe74c3c,\n };\n return colors[level];\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).substr(2, 8).toUpperCase();\n}\n\nexport function formatLog(\n level: string,\n timestamp: string,\n args: unknown[],\n options: LoggerOptions,\n): [string, ...unknown[]] {\n const { formatLog, enableColors = true } = options;\n const coloredLevel = getColor(level, enableColors);\n if (formatLog) {\n return [formatLog(coloredLevel, timestamp, args)];\n }\n return [`${coloredLevel} ${timestamp}`, ...args];\n}\n","import type { LoggerOptions, LogLevel, TimestampTypes } from './types';\nimport {\n formatTimestamp,\n formatLog,\n TIMESTAMP_TYPES,\n getDiscordColor,\n generateId,\n} from './utils';\n\nimport type { TimestampType } from './types';\n\nconst defaultFormatTimestamp = (\n types: TimestampTypes,\n date: Date = new Date(),\n): [TimestampType, string] => [types.ISO, date.toISOString()];\n\nconst LOG_LEVEL_PRIORITIES: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * A simple logger with colored outputs and timestamps.\n */\nexport class Logger {\n private options: LoggerOptions;\n private level: LogLevel;\n\n constructor(options: LoggerOptions = {}) {\n this.options = {\n enableColors: options.enableColors ?? true,\n formatTimestamp: options.formatTimestamp ?? defaultFormatTimestamp,\n formatLog: options.formatLog,\n discord: options.discord,\n };\n this.level = options.level ?? 'debug';\n }\n\n /**\n * Sets the minimum log level for filtering messages.\n * @param level - The log level to set.\n */\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n /**\n * Sends a log message to Discord via webhook if configured.\n * @param level - The log level.\n * @param timestamp - The formatted timestamp.\n * @param args - The log arguments.\n */\n private async sendToDiscord(\n level: LogLevel,\n timestamp: string,\n args: unknown[],\n ): Promise<void> {\n const discord = this.options.discord;\n if (!discord?.enable) return;\n\n try {\n new URL(discord.webhookURL);\n } catch {\n return;\n }\n\n const message = args\n .map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))\n .join(' ');\n\n const title = `${level.toUpperCase()}-${generateId()}`;\n\n const embed = discord.formatEmbed\n ? discord.formatEmbed(level, timestamp, message)\n : {\n title,\n description: message,\n timestamp: new Date().toISOString(),\n color: getDiscordColor(level),\n };\n\n await fetch(discord.webhookURL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ embeds: [embed] }),\n }).catch(() => {});\n }\n\n /**\n * Checks if a log level should be output based on the current log level.\n * @param level - The log level to check.\n * @returns True if the message should be logged.\n */\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVEL_PRIORITIES[level] >= LOG_LEVEL_PRIORITIES[this.level];\n }\n\n /**\n * Logs an info message.\n * @param args - The arguments to log.\n */\n info(...args: unknown[]): void {\n if (!this.shouldLog('info')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[INFO]', timestamp, args, this.options));\n this.sendToDiscord('info', timestamp, args);\n }\n\n /**\n * Logs a warning message.\n * @param args - The arguments to log.\n */\n warn(...args: unknown[]): void {\n if (!this.shouldLog('warn')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[WARN]', timestamp, args, this.options));\n this.sendToDiscord('warn', timestamp, args);\n }\n\n /**\n * Logs an error message.\n * @param args - The arguments to log.\n */\n error(...args: unknown[]): void {\n if (!this.shouldLog('error')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[ERROR]', timestamp, args, this.options));\n this.sendToDiscord('error', timestamp, args);\n }\n\n /**\n * Logs a debug message.\n * @param args - The arguments to log.\n */\n debug(...args: unknown[]): void {\n if (!this.shouldLog('debug')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[DEBUG]', timestamp, args, this.options));\n this.sendToDiscord('debug', timestamp, args);\n }\n}\n"],"mappings":"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","names":["chalk","formatLog"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/logger.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { LoggerOptions, TimestampTypes, LogLevel } from './types';\n\nexport const TIMESTAMP_TYPES: TimestampTypes = {\n ISO: 'iso',\n Locale: 'locale',\n Custom: 'custom',\n};\n\nexport function formatTimestamp(\n formatTimestampFn: NonNullable<LoggerOptions['formatTimestamp']>,\n types: TimestampTypes,\n date: Date = new Date(),\n): string {\n const [, timestamp] = formatTimestampFn(types, date);\n return timestamp;\n}\n\nexport function getColor(level: string, enableColors: boolean): string {\n if (!enableColors) return level;\n const colors: Record<string, string> = {\n '[INFO]': chalk.blue(level),\n '[WARN]': chalk.yellow(level),\n '[ERROR]': chalk.red(level),\n '[DEBUG]': chalk.gray(level),\n };\n return colors[level] || level;\n}\n\nexport function getDiscordColor(level: LogLevel): number {\n const colors: Record<LogLevel, number> = {\n debug: 0x95a5a6,\n info: 0x3498db,\n warn: 0xf39c12,\n error: 0xe74c3c,\n };\n return colors[level];\n}\n\nexport function generateId(): string {\n return Math.random().toString(36).substr(2, 8).toUpperCase();\n}\n\nexport function formatLog(\n level: string,\n timestamp: string,\n args: unknown[],\n options: LoggerOptions,\n): [string, ...unknown[]] {\n const { formatLog, enableColors = true } = options;\n const coloredLevel = getColor(level, enableColors);\n if (formatLog) {\n return [formatLog(coloredLevel, timestamp, args)];\n }\n return [`${coloredLevel} ${timestamp}`, ...args];\n}\n","import type { LoggerOptions, LogLevel, TimestampTypes } from './types';\nimport {\n formatTimestamp,\n formatLog,\n TIMESTAMP_TYPES,\n getDiscordColor,\n generateId,\n} from './utils';\n\nimport type { TimestampType } from './types';\n\nconst defaultFormatTimestamp = (\n types: TimestampTypes,\n date: Date = new Date(),\n): [TimestampType, string] => [types.ISO, date.toISOString()];\n\nconst LOG_LEVEL_PRIORITIES: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * A simple logger with colored outputs and timestamps.\n */\nexport class Logger {\n private options: LoggerOptions;\n private level: LogLevel;\n\n constructor(options: LoggerOptions = {}) {\n this.options = {\n enableColors: options.enableColors ?? true,\n formatTimestamp: options.formatTimestamp ?? defaultFormatTimestamp,\n formatLog: options.formatLog,\n discord: options.discord,\n };\n this.level = options.level ?? 'debug';\n }\n\n /**\n * Sets the minimum log level for filtering messages.\n * @param level - The log level to set.\n */\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n /**\n * Sends a log message to Discord via webhook if configured.\n * @param level - The log level.\n * @param timestamp - The formatted timestamp.\n * @param args - The log arguments.\n */\n private async sendToDiscord(\n level: LogLevel,\n timestamp: string,\n args: unknown[],\n ): Promise<void> {\n const discord = this.options.discord;\n if (!discord?.enable) return;\n\n try {\n new URL(discord.webhookURL);\n } catch {\n return;\n }\n\n const message = args\n .map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))\n .join(' ');\n\n const title = `${level.toUpperCase()}-${generateId()}`;\n\n const embed = discord.formatEmbed\n ? discord.formatEmbed(level, timestamp, message)\n : {\n title,\n description: message,\n timestamp: new Date().toISOString(),\n color: getDiscordColor(level),\n };\n\n await fetch(discord.webhookURL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ embeds: [embed] }),\n }).catch(() => {});\n }\n\n /**\n * Checks if a log level should be output based on the current log level.\n * @param level - The log level to check.\n * @returns True if the message should be logged.\n */\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVEL_PRIORITIES[level] >= LOG_LEVEL_PRIORITIES[this.level];\n }\n\n /**\n * Logs an info message.\n * @param args - The arguments to log.\n */\n info(...args: unknown[]): void {\n if (!this.shouldLog('info')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[INFO]', timestamp, args, this.options));\n this.sendToDiscord('info', timestamp, args);\n }\n\n /**\n * Logs a warning message.\n * @param args - The arguments to log.\n */\n warn(...args: unknown[]): void {\n if (!this.shouldLog('warn')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[WARN]', timestamp, args, this.options));\n this.sendToDiscord('warn', timestamp, args);\n }\n\n /**\n * Logs an error message.\n * @param args - The arguments to log.\n */\n error(...args: unknown[]): void {\n if (!this.shouldLog('error')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[ERROR]', timestamp, args, this.options));\n this.sendToDiscord('error', timestamp, args);\n }\n\n /**\n * Logs a debug message.\n * @param args - The arguments to log.\n */\n debug(...args: unknown[]): void {\n if (!this.shouldLog('debug')) return;\n const timestamp = formatTimestamp(\n this.options.formatTimestamp!,\n TIMESTAMP_TYPES,\n );\n console.log(...formatLog('[DEBUG]', timestamp, args, this.options));\n this.sendToDiscord('debug', timestamp, args);\n }\n}\n"],"mappings":"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","names":["formatLog"]}