@rawnodes/logger 1.7.0 → 1.9.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/dist/index.mjs CHANGED
@@ -2,6 +2,9 @@ import { createLogger, transports, format } from 'winston';
2
2
  import { AsyncLocalStorage } from 'async_hooks';
3
3
  import DailyRotateFile from 'winston-daily-rotate-file';
4
4
  import { inspect } from 'util';
5
+ import TransportStream from 'winston-transport';
6
+ import { CloudWatchLogsClient, PutLogEventsCommand, CreateLogGroupCommand, CreateLogStreamCommand, DescribeLogStreamsCommand } from '@aws-sdk/client-cloudwatch-logs';
7
+ import { z } from 'zod';
5
8
  import { randomUUID } from 'crypto';
6
9
 
7
10
  // src/state.ts
@@ -15,6 +18,26 @@ var LoggerStore = class {
15
18
  }
16
19
  };
17
20
 
21
+ // src/types.ts
22
+ var LOG_LEVELS = {
23
+ off: -1,
24
+ error: 0,
25
+ warn: 1,
26
+ info: 2,
27
+ http: 3,
28
+ verbose: 4,
29
+ debug: 5,
30
+ silly: 6
31
+ };
32
+ function isValidLogLevel(level) {
33
+ return level in LOG_LEVELS;
34
+ }
35
+ function assertLogLevel(level) {
36
+ if (!isValidLogLevel(level)) {
37
+ throw new Error(`Invalid log level: "${level}". Valid levels: ${Object.keys(LOG_LEVELS).join(", ")}`);
38
+ }
39
+ }
40
+
18
41
  // src/utils/mask-secrets.ts
19
42
  var DEFAULT_SECRET_PATTERNS = [
20
43
  "password",
@@ -169,6 +192,20 @@ function maskSecretsFormat(options) {
169
192
  return maskSecrets(info, options);
170
193
  })();
171
194
  }
195
+ function createFilterFormat(defaultLevel, rules, store) {
196
+ if (!rules?.length && defaultLevel === void 0) {
197
+ return format((info) => info)();
198
+ }
199
+ return format((info) => {
200
+ const logLevel = info.level;
201
+ const context = info.context;
202
+ const storeContext = store.getStore();
203
+ const matchingRule = rules?.find((rule) => matchesContext(storeContext, context, rule.match));
204
+ const effectiveLevel = matchingRule?.level ?? defaultLevel ?? "silly";
205
+ if (effectiveLevel === "off") return false;
206
+ return LOG_LEVELS[logLevel] <= LOG_LEVELS[effectiveLevel] ? info : false;
207
+ })();
208
+ }
172
209
  function createPlainFormat(store) {
173
210
  return format.combine(
174
211
  format.errors({ stack: true }),
@@ -233,17 +270,461 @@ function createFormat(logFormat, store) {
233
270
  }
234
271
  }
235
272
 
273
+ // src/transports/buffer.ts
274
+ var MessageBuffer = class {
275
+ constructor(options) {
276
+ this.options = options;
277
+ }
278
+ queue = [];
279
+ timer = null;
280
+ flushing = false;
281
+ closed = false;
282
+ add(message) {
283
+ if (this.closed) return;
284
+ this.queue.push(message);
285
+ if (this.queue.length >= this.options.batchSize) {
286
+ void this.flush();
287
+ } else {
288
+ this.scheduleFlush();
289
+ }
290
+ }
291
+ async flush() {
292
+ if (this.flushing || this.queue.length === 0) return;
293
+ this.flushing = true;
294
+ this.clearTimer();
295
+ const messages = this.queue.splice(0, this.options.batchSize);
296
+ try {
297
+ await this.sendWithRetry(messages);
298
+ } catch (error) {
299
+ this.options.onError?.(error, messages);
300
+ } finally {
301
+ this.flushing = false;
302
+ if (this.queue.length > 0 && !this.closed) {
303
+ void this.flush();
304
+ }
305
+ }
306
+ }
307
+ async close() {
308
+ this.closed = true;
309
+ this.clearTimer();
310
+ while (this.queue.length > 0) {
311
+ await this.flush();
312
+ }
313
+ }
314
+ scheduleFlush() {
315
+ if (this.timer || this.closed) return;
316
+ this.timer = setTimeout(() => {
317
+ this.timer = null;
318
+ void this.flush();
319
+ }, this.options.flushInterval);
320
+ }
321
+ clearTimer() {
322
+ if (this.timer) {
323
+ clearTimeout(this.timer);
324
+ this.timer = null;
325
+ }
326
+ }
327
+ async sendWithRetry(messages) {
328
+ let lastError = null;
329
+ for (let attempt = 0; attempt < this.options.maxRetries; attempt++) {
330
+ try {
331
+ await this.options.onFlush(messages);
332
+ return;
333
+ } catch (error) {
334
+ lastError = error;
335
+ if (attempt < this.options.maxRetries - 1) {
336
+ await this.delay(this.options.retryDelay * Math.pow(2, attempt));
337
+ }
338
+ }
339
+ }
340
+ throw lastError;
341
+ }
342
+ delay(ms) {
343
+ return new Promise((resolve) => setTimeout(resolve, ms));
344
+ }
345
+ };
346
+
347
+ // src/transports/base-http.ts
348
+ var DEFAULT_OPTIONS = {
349
+ batchSize: 10,
350
+ flushInterval: 5e3,
351
+ maxRetries: 3,
352
+ retryDelay: 1e3
353
+ };
354
+ var BaseHttpTransport = class extends TransportStream {
355
+ buffer;
356
+ constructor(opts = {}) {
357
+ super();
358
+ this.buffer = new MessageBuffer({
359
+ batchSize: opts.batchSize ?? DEFAULT_OPTIONS.batchSize,
360
+ flushInterval: opts.flushInterval ?? DEFAULT_OPTIONS.flushInterval,
361
+ maxRetries: opts.maxRetries ?? DEFAULT_OPTIONS.maxRetries,
362
+ retryDelay: opts.retryDelay ?? DEFAULT_OPTIONS.retryDelay,
363
+ onFlush: this.sendBatch.bind(this),
364
+ onError: this.handleError.bind(this)
365
+ });
366
+ }
367
+ log(info, callback) {
368
+ const message = this.transformMessage(info);
369
+ this.buffer.add(message);
370
+ callback();
371
+ }
372
+ close() {
373
+ return this.buffer.close();
374
+ }
375
+ transformMessage(info) {
376
+ const { level, message, timestamp, context, ...meta } = info;
377
+ return {
378
+ level,
379
+ message: String(message),
380
+ timestamp: timestamp ? new Date(String(timestamp)) : /* @__PURE__ */ new Date(),
381
+ context,
382
+ meta: Object.keys(meta).length > 0 ? meta : void 0
383
+ };
384
+ }
385
+ handleError(error, messages) {
386
+ console.error(
387
+ `[${this.constructor.name}] Failed to send ${messages.length} messages:`,
388
+ error.message
389
+ );
390
+ this.emit("error", error);
391
+ }
392
+ };
393
+
394
+ // src/transports/discord.ts
395
+ var DEFAULT_EMBED_COLORS = {
396
+ off: 0,
397
+ error: 15548997,
398
+ warn: 16705372,
399
+ info: 5763719,
400
+ http: 5793266,
401
+ verbose: 10181046,
402
+ debug: 3447003,
403
+ silly: 9807270
404
+ };
405
+ var DiscordTransport = class extends BaseHttpTransport {
406
+ config;
407
+ constructor(config) {
408
+ super({
409
+ batchSize: config.batchSize ?? 10,
410
+ flushInterval: config.flushInterval ?? 2e3,
411
+ maxRetries: config.maxRetries,
412
+ retryDelay: config.retryDelay
413
+ });
414
+ this.config = config;
415
+ }
416
+ async sendBatch(messages) {
417
+ const chunks = this.chunkArray(messages, 10);
418
+ for (const chunk of chunks) {
419
+ const payload = {
420
+ username: this.config.username,
421
+ avatar_url: this.config.avatarUrl,
422
+ embeds: chunk.map((msg) => this.createEmbed(msg))
423
+ };
424
+ await this.sendWebhook(payload);
425
+ }
426
+ }
427
+ createEmbed(msg) {
428
+ const color = this.config.embedColors?.[msg.level] ?? DEFAULT_EMBED_COLORS[msg.level];
429
+ const embed = {
430
+ title: `[${msg.level.toUpperCase()}] ${msg.context || "APP"}`,
431
+ description: msg.message.slice(0, 4096),
432
+ // Discord limit
433
+ color
434
+ };
435
+ if (this.config.includeTimestamp !== false) {
436
+ embed.timestamp = msg.timestamp.toISOString();
437
+ }
438
+ if (this.config.includeMeta !== false && msg.meta) {
439
+ embed.fields = this.metaToFields(msg.meta);
440
+ }
441
+ return embed;
442
+ }
443
+ metaToFields(meta) {
444
+ const maxFields = this.config.maxEmbedFields ?? 25;
445
+ const fields = [];
446
+ for (const [key, value] of Object.entries(meta)) {
447
+ if (fields.length >= maxFields) break;
448
+ let strValue;
449
+ if (typeof value === "object") {
450
+ strValue = "```json\n" + JSON.stringify(value, null, 2).slice(0, 1e3) + "\n```";
451
+ } else {
452
+ strValue = String(value).slice(0, 1024);
453
+ }
454
+ fields.push({
455
+ name: key.slice(0, 256),
456
+ value: strValue,
457
+ inline: typeof value !== "object" && String(value).length < 50
458
+ });
459
+ }
460
+ return fields;
461
+ }
462
+ async sendWebhook(payload) {
463
+ const response = await fetch(this.config.webhookUrl, {
464
+ method: "POST",
465
+ headers: { "Content-Type": "application/json" },
466
+ body: JSON.stringify(payload)
467
+ });
468
+ if (!response.ok) {
469
+ const text = await response.text();
470
+ throw new Error(`Discord webhook failed: ${response.status} ${text}`);
471
+ }
472
+ }
473
+ chunkArray(array, size) {
474
+ const chunks = [];
475
+ for (let i = 0; i < array.length; i += size) {
476
+ chunks.push(array.slice(i, i + size));
477
+ }
478
+ return chunks;
479
+ }
480
+ };
481
+
482
+ // src/transports/telegram.ts
483
+ var LEVEL_EMOJI = {
484
+ off: "",
485
+ error: "\u{1F534}",
486
+ warn: "\u{1F7E1}",
487
+ info: "\u{1F7E2}",
488
+ http: "\u{1F535}",
489
+ verbose: "\u{1F7E3}",
490
+ debug: "\u26AA",
491
+ silly: "\u26AB"
492
+ };
493
+ var TelegramTransport = class extends BaseHttpTransport {
494
+ config;
495
+ apiUrl;
496
+ constructor(config) {
497
+ super({
498
+ batchSize: config.batchSize ?? 20,
499
+ flushInterval: config.flushInterval ?? 1e3,
500
+ maxRetries: config.maxRetries,
501
+ retryDelay: config.retryDelay
502
+ });
503
+ this.config = config;
504
+ this.apiUrl = `https://api.telegram.org/bot${config.botToken}`;
505
+ }
506
+ async sendBatch(messages) {
507
+ const text = this.formatBatchMessage(messages);
508
+ await this.sendMessage(text, messages);
509
+ }
510
+ formatBatchMessage(messages) {
511
+ const parseMode = this.config.parseMode ?? "Markdown";
512
+ return messages.map((msg) => {
513
+ if (parseMode === "HTML") {
514
+ return this.formatHtml(msg);
515
+ }
516
+ return this.formatMarkdown(msg, parseMode === "MarkdownV2");
517
+ }).join("\n\n---\n\n");
518
+ }
519
+ formatMarkdown(msg, v2) {
520
+ const emoji = LEVEL_EMOJI[msg.level];
521
+ const escape = v2 ? this.escapeMarkdownV2.bind(this) : (s) => s;
522
+ let text = `${emoji} *${msg.level.toUpperCase()}* \\[${escape(msg.context || "APP")}\\]
523
+ `;
524
+ text += escape(msg.message);
525
+ if (msg.meta && Object.keys(msg.meta).length > 0) {
526
+ const metaStr = JSON.stringify(msg.meta, null, 2);
527
+ text += "\n```json\n" + metaStr + "\n```";
528
+ }
529
+ return text;
530
+ }
531
+ formatHtml(msg) {
532
+ const emoji = LEVEL_EMOJI[msg.level];
533
+ let text = `${emoji} <b>${msg.level.toUpperCase()}</b> [${this.escapeHtml(msg.context || "APP")}]
534
+ `;
535
+ text += this.escapeHtml(msg.message);
536
+ if (msg.meta && Object.keys(msg.meta).length > 0) {
537
+ const metaStr = JSON.stringify(msg.meta, null, 2);
538
+ text += "\n<pre>" + this.escapeHtml(metaStr) + "</pre>";
539
+ }
540
+ return text;
541
+ }
542
+ shouldMute(messages) {
543
+ if (this.config.disableNotification !== void 0) {
544
+ return this.config.disableNotification;
545
+ }
546
+ return !messages.some((m) => m.level === "error");
547
+ }
548
+ async sendMessage(text, messages) {
549
+ const body = {
550
+ chat_id: this.config.chatId,
551
+ text,
552
+ parse_mode: this.config.parseMode ?? "Markdown",
553
+ disable_notification: this.shouldMute(messages)
554
+ };
555
+ if (this.config.threadId) {
556
+ body.message_thread_id = this.config.threadId;
557
+ }
558
+ if (this.config.replyToMessageId) {
559
+ body.reply_to_message_id = this.config.replyToMessageId;
560
+ }
561
+ const response = await fetch(`${this.apiUrl}/sendMessage`, {
562
+ method: "POST",
563
+ headers: { "Content-Type": "application/json" },
564
+ body: JSON.stringify(body)
565
+ });
566
+ if (!response.ok) {
567
+ const result = await response.json();
568
+ throw new Error(`Telegram API failed: ${response.status} ${JSON.stringify(result)}`);
569
+ }
570
+ }
571
+ escapeMarkdownV2(text) {
572
+ return text.replace(/[_*[\]()~`>#+\-=|{}.!]/g, "\\$&");
573
+ }
574
+ escapeHtml(text) {
575
+ const entities = {
576
+ "&": "&amp;",
577
+ "<": "&lt;",
578
+ ">": "&gt;",
579
+ '"': "&quot;",
580
+ "'": "&#39;"
581
+ };
582
+ return text.replace(/[&<>"']/g, (c) => entities[c] || c);
583
+ }
584
+ };
585
+ var CloudWatchTransport = class extends BaseHttpTransport {
586
+ config;
587
+ client;
588
+ sequenceToken;
589
+ initialized = false;
590
+ initPromise = null;
591
+ constructor(config) {
592
+ super({
593
+ batchSize: config.batchSize ?? 100,
594
+ flushInterval: config.flushInterval ?? 1e3,
595
+ maxRetries: config.maxRetries,
596
+ retryDelay: config.retryDelay
597
+ });
598
+ this.config = config;
599
+ this.client = new CloudWatchLogsClient({
600
+ region: config.region,
601
+ credentials: {
602
+ accessKeyId: config.accessKeyId,
603
+ secretAccessKey: config.secretAccessKey
604
+ }
605
+ });
606
+ }
607
+ async sendBatch(messages) {
608
+ await this.ensureInitialized();
609
+ const logEvents = messages.map((msg) => ({
610
+ timestamp: msg.timestamp.getTime(),
611
+ message: JSON.stringify({
612
+ level: msg.level,
613
+ message: msg.message,
614
+ context: msg.context,
615
+ ...msg.meta
616
+ })
617
+ }));
618
+ logEvents.sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
619
+ const command = new PutLogEventsCommand({
620
+ logGroupName: this.config.logGroupName,
621
+ logStreamName: this.config.logStreamName,
622
+ logEvents,
623
+ sequenceToken: this.sequenceToken
624
+ });
625
+ try {
626
+ const response = await this.client.send(command);
627
+ this.sequenceToken = response.nextSequenceToken;
628
+ } catch (error) {
629
+ if (this.isInvalidSequenceTokenError(error)) {
630
+ await this.fetchSequenceToken();
631
+ const retryCommand = new PutLogEventsCommand({
632
+ logGroupName: this.config.logGroupName,
633
+ logStreamName: this.config.logStreamName,
634
+ logEvents,
635
+ sequenceToken: this.sequenceToken
636
+ });
637
+ const response = await this.client.send(retryCommand);
638
+ this.sequenceToken = response.nextSequenceToken;
639
+ } else {
640
+ throw error;
641
+ }
642
+ }
643
+ }
644
+ async ensureInitialized() {
645
+ if (this.initialized) return;
646
+ if (!this.initPromise) {
647
+ this.initPromise = this.initialize();
648
+ }
649
+ await this.initPromise;
650
+ }
651
+ async initialize() {
652
+ if (this.config.createLogGroup) {
653
+ await this.createLogGroupIfNotExists();
654
+ }
655
+ if (this.config.createLogStream !== false) {
656
+ await this.createLogStreamIfNotExists();
657
+ }
658
+ await this.fetchSequenceToken();
659
+ this.initialized = true;
660
+ }
661
+ async createLogGroupIfNotExists() {
662
+ try {
663
+ await this.client.send(
664
+ new CreateLogGroupCommand({
665
+ logGroupName: this.config.logGroupName
666
+ })
667
+ );
668
+ } catch (error) {
669
+ if (!this.isResourceAlreadyExistsError(error)) {
670
+ throw error;
671
+ }
672
+ }
673
+ }
674
+ async createLogStreamIfNotExists() {
675
+ try {
676
+ await this.client.send(
677
+ new CreateLogStreamCommand({
678
+ logGroupName: this.config.logGroupName,
679
+ logStreamName: this.config.logStreamName
680
+ })
681
+ );
682
+ } catch (error) {
683
+ if (!this.isResourceAlreadyExistsError(error)) {
684
+ throw error;
685
+ }
686
+ }
687
+ }
688
+ async fetchSequenceToken() {
689
+ const response = await this.client.send(
690
+ new DescribeLogStreamsCommand({
691
+ logGroupName: this.config.logGroupName,
692
+ logStreamNamePrefix: this.config.logStreamName,
693
+ limit: 1
694
+ })
695
+ );
696
+ const stream = response.logStreams?.find((s) => s.logStreamName === this.config.logStreamName);
697
+ this.sequenceToken = stream?.uploadSequenceToken;
698
+ }
699
+ isResourceAlreadyExistsError(error) {
700
+ return typeof error === "object" && error !== null && "name" in error && error.name === "ResourceAlreadyExistsException";
701
+ }
702
+ isInvalidSequenceTokenError(error) {
703
+ return typeof error === "object" && error !== null && "name" in error && error.name === "InvalidSequenceTokenException";
704
+ }
705
+ };
706
+
236
707
  // src/transports.ts
708
+ function toArray(value) {
709
+ if (!value) return [];
710
+ return Array.isArray(value) ? value : [value];
711
+ }
237
712
  function createTransports(config, store) {
238
713
  const result = [
239
714
  new transports.Console({
240
- format: createFormat(config.console.format, store)
715
+ format: format.combine(
716
+ createFilterFormat(config.console.level, config.console.rules, store),
717
+ createFormat(config.console.format, store)
718
+ )
241
719
  })
242
720
  ];
243
721
  if (config.file) {
244
722
  result.push(
245
723
  new DailyRotateFile({
246
- format: createFormat(config.file.format, store),
724
+ format: format.combine(
725
+ createFilterFormat(config.file.level, config.file.rules, store),
726
+ createFormat(config.file.format, store)
727
+ ),
247
728
  dirname: config.file.dirname,
248
729
  filename: config.file.filename,
249
730
  datePattern: config.file.datePattern ?? "YYYY-MM-DD",
@@ -253,6 +734,30 @@ function createTransports(config, store) {
253
734
  })
254
735
  );
255
736
  }
737
+ for (const discordConfig of toArray(config.discord)) {
738
+ const discord = new DiscordTransport(discordConfig);
739
+ discord.format = format.combine(
740
+ createFilterFormat(discordConfig.level, discordConfig.rules, store),
741
+ format.timestamp()
742
+ );
743
+ result.push(discord);
744
+ }
745
+ for (const telegramConfig of toArray(config.telegram)) {
746
+ const telegram = new TelegramTransport(telegramConfig);
747
+ telegram.format = format.combine(
748
+ createFilterFormat(telegramConfig.level, telegramConfig.rules, store),
749
+ format.timestamp()
750
+ );
751
+ result.push(telegram);
752
+ }
753
+ for (const cloudwatchConfig of toArray(config.cloudwatch)) {
754
+ const cloudwatch = new CloudWatchTransport(cloudwatchConfig);
755
+ cloudwatch.format = format.combine(
756
+ createFilterFormat(cloudwatchConfig.level, cloudwatchConfig.rules, store),
757
+ format.timestamp()
758
+ );
759
+ result.push(cloudwatch);
760
+ }
256
761
  return result;
257
762
  }
258
763
  function createExceptionHandlers(config, store) {
@@ -277,25 +782,6 @@ function createExceptionHandlers(config, store) {
277
782
  return result;
278
783
  }
279
784
 
280
- // src/types.ts
281
- var LOG_LEVELS = {
282
- error: 0,
283
- warn: 1,
284
- info: 2,
285
- http: 3,
286
- verbose: 4,
287
- debug: 5,
288
- silly: 6
289
- };
290
- function isValidLogLevel(level) {
291
- return level in LOG_LEVELS;
292
- }
293
- function assertLogLevel(level) {
294
- if (!isValidLogLevel(level)) {
295
- throw new Error(`Invalid log level: "${level}". Valid levels: ${Object.keys(LOG_LEVELS).join(", ")}`);
296
- }
297
- }
298
-
299
785
  // src/state.ts
300
786
  function parseLevelConfig(level) {
301
787
  if (typeof level === "string") {
@@ -350,6 +836,81 @@ function matchesContext(storeContext, loggerContext, match) {
350
836
  const combined = { ...storeContext, context: loggerContext };
351
837
  return Object.entries(match).every(([key, value]) => combined[key] === value);
352
838
  }
839
+ var LogLevelSchema = z.enum(["off", "error", "warn", "info", "http", "verbose", "debug", "silly"]);
840
+ var LogFormatSchema = z.enum(["json", "plain", "logfmt", "simple"]);
841
+ var LevelRuleSchema = z.object({
842
+ match: z.record(z.string(), z.unknown()),
843
+ level: LogLevelSchema
844
+ });
845
+ var ConsoleConfigSchema = z.object({
846
+ format: LogFormatSchema,
847
+ level: LogLevelSchema.optional(),
848
+ rules: z.array(LevelRuleSchema).optional()
849
+ });
850
+ var FileConfigSchema = z.object({
851
+ format: LogFormatSchema,
852
+ level: LogLevelSchema.optional(),
853
+ rules: z.array(LevelRuleSchema).optional(),
854
+ dirname: z.string().min(1, "dirname is required"),
855
+ filename: z.string().min(1, "filename is required"),
856
+ datePattern: z.string().optional(),
857
+ zippedArchive: z.boolean().optional(),
858
+ maxSize: z.string().optional(),
859
+ maxFiles: z.string().optional()
860
+ });
861
+ var HttpTransportBaseConfigSchema = z.object({
862
+ level: LogLevelSchema.optional(),
863
+ rules: z.array(LevelRuleSchema).optional(),
864
+ batchSize: z.number().int().positive().optional(),
865
+ flushInterval: z.number().int().positive().optional(),
866
+ maxRetries: z.number().int().nonnegative().optional(),
867
+ retryDelay: z.number().int().positive().optional()
868
+ });
869
+ var DiscordConfigSchema = HttpTransportBaseConfigSchema.extend({
870
+ webhookUrl: z.url("webhookUrl must be a valid URL"),
871
+ username: z.string().optional(),
872
+ avatarUrl: z.url().optional(),
873
+ embedColors: z.record(z.string(), z.number().int()).optional(),
874
+ includeTimestamp: z.boolean().optional(),
875
+ includeMeta: z.boolean().optional(),
876
+ maxEmbedFields: z.number().int().min(1).max(25).optional()
877
+ });
878
+ var TelegramConfigSchema = HttpTransportBaseConfigSchema.extend({
879
+ botToken: z.string().min(1, "botToken is required"),
880
+ chatId: z.union([z.string(), z.number()]),
881
+ parseMode: z.enum(["Markdown", "MarkdownV2", "HTML"]).optional(),
882
+ disableNotification: z.boolean().optional(),
883
+ threadId: z.number().int().optional(),
884
+ replyToMessageId: z.number().int().optional()
885
+ });
886
+ var CloudWatchConfigSchema = HttpTransportBaseConfigSchema.extend({
887
+ logGroupName: z.string().min(1, "logGroupName is required"),
888
+ logStreamName: z.string().min(1, "logStreamName is required"),
889
+ region: z.string().min(1, "region is required"),
890
+ accessKeyId: z.string().min(1, "accessKeyId is required"),
891
+ secretAccessKey: z.string().min(1, "secretAccessKey is required"),
892
+ createLogGroup: z.boolean().optional(),
893
+ createLogStream: z.boolean().optional()
894
+ });
895
+ var LevelConfigObjectSchema = z.object({
896
+ default: LogLevelSchema,
897
+ rules: z.array(LevelRuleSchema).optional()
898
+ });
899
+ var LevelConfigSchema = z.union([LogLevelSchema, LevelConfigObjectSchema]);
900
+ var LoggerConfigSchema = z.object({
901
+ level: LevelConfigSchema,
902
+ console: ConsoleConfigSchema,
903
+ file: FileConfigSchema.optional(),
904
+ discord: z.union([DiscordConfigSchema, z.array(DiscordConfigSchema)]).optional(),
905
+ telegram: z.union([TelegramConfigSchema, z.array(TelegramConfigSchema)]).optional(),
906
+ cloudwatch: z.union([CloudWatchConfigSchema, z.array(CloudWatchConfigSchema)]).optional()
907
+ });
908
+ function validateConfig(config) {
909
+ return LoggerConfigSchema.parse(config);
910
+ }
911
+ function safeValidateConfig(config) {
912
+ return LoggerConfigSchema.safeParse(config);
913
+ }
353
914
 
354
915
  // src/logger.ts
355
916
  var Logger = class _Logger {
@@ -358,7 +919,8 @@ var Logger = class _Logger {
358
919
  this.context = context;
359
920
  }
360
921
  static create(config, store) {
361
- const state = createState(config, store);
922
+ const validatedConfig = validateConfig(config);
923
+ const state = createState(validatedConfig, store);
362
924
  return new _Logger(state, "APP");
363
925
  }
364
926
  for(context) {
@@ -538,6 +1100,6 @@ function getOrGenerateRequestId(headers, options = {}) {
538
1100
  return extractRequestId(headers) ?? generateRequestId(options);
539
1101
  }
540
1102
 
541
- export { LOG_LEVELS, Logger, LoggerStore, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatLogfmt, formatLogfmtValue, generateRequestId, getOrGenerateRequestId, isValidLogLevel, maskSecrets, measureAsync, measureSync };
1103
+ export { BaseHttpTransport, CloudWatchConfigSchema, CloudWatchTransport, ConsoleConfigSchema, DiscordConfigSchema, DiscordTransport, FileConfigSchema, HttpTransportBaseConfigSchema, LOG_LEVELS, LevelConfigObjectSchema, LevelConfigSchema, LevelRuleSchema, LogFormatSchema, LogLevelSchema, Logger, LoggerConfigSchema, LoggerStore, MessageBuffer, TelegramConfigSchema, TelegramTransport, assertLogLevel, createMasker, createSingletonLogger, extractRequestId, flattenObject, formatLogfmt, formatLogfmtValue, generateRequestId, getOrGenerateRequestId, isValidLogLevel, maskSecrets, matchesContext, measureAsync, measureSync, safeValidateConfig, validateConfig };
542
1104
  //# sourceMappingURL=index.mjs.map
543
1105
  //# sourceMappingURL=index.mjs.map