@mrxsys/mrx-core 2.11.0-1-and-267-20250925 → 2.11.1-1-and-275-20251023

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.
Files changed (76) hide show
  1. package/dist/{chunk-fp8xg6kq.js → chunk-441xs5k1.js} +1 -1
  2. package/dist/{chunk-bdcsh435.js → chunk-4v86f7gp.js} +5 -5
  3. package/dist/{chunk-00s6t4tw.js → chunk-7t524zqh.js} +4 -4
  4. package/dist/{chunk-d1vp74n0.js → chunk-afd82epa.js} +2 -2
  5. package/dist/{chunk-v9kvw5x7.js → chunk-afyz8rg5.js} +2 -2
  6. package/dist/{chunk-6sfnrhfs.js → chunk-pjv1ekwr.js} +33 -1
  7. package/dist/chunk-rz5p4j3p.js +13 -0
  8. package/dist/{chunk-h9t48r9q.js → chunk-sqts8vyk.js} +16 -2
  9. package/dist/errors/enums/http-status-codes.d.ts +15 -1
  10. package/dist/errors/enums/index.d.ts +1 -1
  11. package/dist/errors/enums/index.js +3 -3
  12. package/dist/errors/http-error.d.ts +3 -3
  13. package/dist/errors/index.js +2 -2
  14. package/dist/errors/utils/index.js +2 -2
  15. package/dist/modules/database/enums/database-error-keys.d.ts +2 -2
  16. package/dist/modules/database/enums/index.js +1 -1
  17. package/dist/modules/database/index.js +5 -5
  18. package/dist/modules/elysia/cache/cache.d.ts +8 -14
  19. package/dist/modules/elysia/cache/index.js +66 -46
  20. package/dist/modules/elysia/cache/types/cache-item.d.ts +0 -1
  21. package/dist/modules/elysia/cache/types/cache-options.d.ts +2 -11
  22. package/dist/modules/elysia/crud/index.js +16 -16
  23. package/dist/modules/elysia/crud/operations/count.d.ts +1 -1
  24. package/dist/modules/elysia/crud/operations/delete.d.ts +1 -1
  25. package/dist/modules/elysia/crud/operations/deleteOne.d.ts +1 -1
  26. package/dist/modules/elysia/crud/operations/find.d.ts +1 -1
  27. package/dist/modules/elysia/crud/operations/findOne.d.ts +1 -1
  28. package/dist/modules/elysia/crud/operations/index.js +7 -7
  29. package/dist/modules/elysia/crud/operations/insert.d.ts +1 -1
  30. package/dist/modules/elysia/crud/operations/update.d.ts +1 -1
  31. package/dist/modules/elysia/crud/operations/updateOne.d.ts +1 -1
  32. package/dist/modules/elysia/db-resolver/db-resolver.d.ts +1 -1
  33. package/dist/modules/elysia/db-resolver/index.js +6 -6
  34. package/dist/modules/elysia/error/index.js +2 -2
  35. package/dist/modules/elysia/microservice/microservice.d.ts +12 -12
  36. package/dist/modules/elysia/rate-limit/index.js +53 -28
  37. package/dist/modules/elysia/rate-limit/rate-limit.d.ts +361 -32
  38. package/dist/modules/elysia/rate-limit/types/rate-limit-options.d.ts +0 -9
  39. package/dist/modules/jwt/index.js +2 -2
  40. package/dist/modules/kv-store/bun-redis/bun-redis-store.d.ts +25 -0
  41. package/dist/modules/kv-store/bun-redis/index.d.ts +1 -0
  42. package/dist/modules/kv-store/bun-redis/index.js +76 -0
  43. package/dist/modules/kv-store/ioredis/index.js +4 -10
  44. package/dist/modules/kv-store/ioredis/ioredis-store.d.ts +0 -82
  45. package/dist/modules/kv-store/memory/index.js +98 -4
  46. package/dist/modules/kv-store/memory/memory-store.d.ts +0 -84
  47. package/dist/modules/kv-store/types/kv-store.d.ts +2 -2
  48. package/dist/modules/logger/enums/index.js +1 -1
  49. package/dist/modules/logger/enums/logger-error-keys.d.ts +6 -3
  50. package/dist/modules/logger/events/logger-events.d.ts +12 -3
  51. package/dist/modules/logger/index.js +173 -81
  52. package/dist/modules/logger/logger.d.ts +115 -133
  53. package/dist/modules/logger/sinks/console-logger.d.ts +2 -16
  54. package/dist/modules/logger/sinks/devnull-logger.d.ts +8 -0
  55. package/dist/modules/logger/sinks/file-logger/enums/file-logger-error-keys.d.ts +3 -0
  56. package/dist/modules/logger/sinks/file-logger/file-logger.d.ts +25 -0
  57. package/dist/modules/logger/sinks/index.d.ts +4 -2
  58. package/dist/modules/logger/sinks/index.js +54 -31
  59. package/dist/modules/logger/types/index.d.ts +6 -6
  60. package/dist/modules/logger/types/log-levels.d.ts +1 -4
  61. package/dist/modules/logger/types/logger-options.d.ts +41 -0
  62. package/dist/modules/logger/types/logger-sink.d.ts +12 -3
  63. package/dist/modules/logger/types/sink-bodies-intersection.d.ts +2 -0
  64. package/dist/modules/logger/types/sink-body.d.ts +1 -1
  65. package/dist/modules/logger/types/sink-map.d.ts +1 -1
  66. package/dist/modules/repository/index.js +4 -4
  67. package/dist/modules/repository/types/query-options.d.ts +2 -2
  68. package/package.json +30 -25
  69. package/dist/chunk-b23dvm2d.js +0 -29
  70. package/dist/chunk-b96fm9ph.js +0 -10
  71. package/dist/chunk-e30paw8a.js +0 -101
  72. package/dist/modules/elysia/cache/utils/index.d.ts +0 -1
  73. package/dist/modules/elysia/cache/utils/index.js +0 -7
  74. package/dist/modules/logger/sinks/file-logger.d.ts +0 -25
  75. package/dist/modules/logger/types/bodies-intersection.d.ts +0 -2
  76. package/dist/modules/logger/types/log-stream-chunk.d.ts +0 -15
@@ -11,97 +11,15 @@ export declare class IoRedisStore implements KvStore {
11
11
  * Redis client instance.
12
12
  */
13
13
  private readonly _client;
14
- /**
15
- * Creates an IoRedis store instance.
16
- *
17
- * @param options - Redis connection options
18
- */
19
14
  constructor(options: RedisOptions);
20
- /**
21
- * Establishes connection to Redis server.
22
- *
23
- * @throws ({@link BaseError}) - When connection fails
24
- */
25
15
  connect(): Promise<void>;
26
- /**
27
- * Closes the Redis connection gracefully.
28
- *
29
- * @throws ({@link BaseError}) - When closing connection fails
30
- */
31
16
  close(): Promise<void>;
32
- /**
33
- * Retrieves a value from Redis by key.
34
- *
35
- * @template T - The expected type of the stored value
36
- *
37
- * @param key - The key to retrieve
38
- *
39
- * @returns The value associated with the key, or null if not found or expired
40
- */
41
17
  get<T = unknown>(key: string): Promise<T | null>;
42
- /**
43
- * Stores a value in Redis with optional TTL.
44
- *
45
- * @template T - The type of the value being stored
46
- *
47
- * @param key - The key to store the value under
48
- * @param value - The value to store
49
- * @param ttlSec - Time to live in seconds (optional)
50
- */
51
18
  set<T = unknown>(key: string, value: T, ttlSec?: number): Promise<void>;
52
- /**
53
- * Increments a numeric value stored at key by the specified amount.
54
- * If the key does not exist, it is set to 0 before performing the operation.
55
- *
56
- * @param key - The key containing the numeric value
57
- * @param amount - The amount to increment by (default: 1)
58
- *
59
- * @throws ({@link BaseError}) - When the value is not a valid integer
60
- *
61
- * @returns The value after incrementing
62
- */
63
19
  increment(key: string, amount?: number): Promise<number>;
64
- /**
65
- * Decrements a numeric value stored at key by the specified amount.
66
- * If the key does not exist, it is set to 0 before performing the operation.
67
- *
68
- * @param key - The key containing the numeric value
69
- * @param amount - The amount to decrement by (default: 1)
70
- *
71
- * @throws ({@link BaseError}) - When the value is not a valid integer
72
- *
73
- * @returns The value after decrementing
74
- */
75
20
  decrement(key: string, amount?: number): Promise<number>;
76
- /**
77
- * Deletes a key from Redis.
78
- *
79
- * @param key - The key to delete
80
- *
81
- * @returns True if the key was deleted, false if it did not exist
82
- */
83
21
  del(key: string): Promise<boolean>;
84
- /**
85
- * Sets an expiration time for a key.
86
- *
87
- * @param key - The key to set expiration for
88
- * @param ttlSec - Time to live in seconds
89
- *
90
- * @returns True if the expiration was set, false if the key does not exist
91
- */
92
22
  expire(key: string, ttlSec: number): Promise<boolean>;
93
- /**
94
- * Gets the remaining time to live for a key.
95
- *
96
- * @param key - The key to check
97
- *
98
- * @returns Time to live in seconds, -1 if key has no expiration, -2 if key does not exist
99
- */
100
23
  ttl(key: string): Promise<number>;
101
- /**
102
- * Removes all keys from the Redis database.
103
- *
104
- * @returns The number of keys that were deleted
105
- */
106
24
  clean(): Promise<number>;
107
25
  }
@@ -1,9 +1,103 @@
1
1
  // @bun
2
2
  import {
3
- MemoryStore
4
- } from "../../../chunk-e30paw8a.js";
5
- import"../../../chunk-xhhj1gvj.js";
6
- import"../../../chunk-9cgzhc50.js";
3
+ KV_STORE_ERROR_KEYS
4
+ } from "../../../chunk-xhhj1gvj.js";
5
+ import {
6
+ BaseError
7
+ } from "../../../chunk-9cgzhc50.js";
8
+
9
+ // source/modules/kv-store/memory/memory-store.ts
10
+ class MemoryStore {
11
+ _store = new Map;
12
+ _cleanupInterval;
13
+ _cleanupTimer = null;
14
+ constructor(cleanupIntervalMs) {
15
+ this._cleanupInterval = cleanupIntervalMs ?? 300000;
16
+ this._startCleanup();
17
+ }
18
+ get(key) {
19
+ const entry = this._store.get(key);
20
+ if (!entry)
21
+ return null;
22
+ const now = Date.now();
23
+ if (now > entry.expiresAt && entry.expiresAt !== -1) {
24
+ this._store.delete(key);
25
+ return null;
26
+ }
27
+ return entry.value;
28
+ }
29
+ set(key, value, ttlSec) {
30
+ const expiresAt = ttlSec ? Date.now() + ttlSec * 1000 : -1;
31
+ this._store.set(key, { value, expiresAt });
32
+ }
33
+ increment(key, amount = 1) {
34
+ const current = this.get(key);
35
+ const entry = this._store.get(key);
36
+ if (current !== null && typeof current !== "number")
37
+ throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER);
38
+ const currentValue = current ?? 0;
39
+ const newValue = currentValue + amount;
40
+ const expiresAt = entry ? entry.expiresAt : -1;
41
+ this._store.set(key, { value: newValue, expiresAt });
42
+ return newValue;
43
+ }
44
+ decrement(key, amount = 1) {
45
+ const current = this.get(key);
46
+ const entry = this._store.get(key);
47
+ if (current !== null && typeof current !== "number")
48
+ throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER);
49
+ const currentValue = current ?? 0;
50
+ const newValue = currentValue - amount;
51
+ const expiresAt = entry ? entry.expiresAt : -1;
52
+ this._store.set(key, { value: newValue, expiresAt });
53
+ return newValue;
54
+ }
55
+ del(key) {
56
+ return this._store.delete(key);
57
+ }
58
+ expire(key, ttlSec) {
59
+ const entry = this._store.get(key);
60
+ if (!entry)
61
+ return false;
62
+ entry.expiresAt = Date.now() + ttlSec * 1000;
63
+ return true;
64
+ }
65
+ ttl(key) {
66
+ const entry = this._store.get(key);
67
+ if (!entry)
68
+ return -1;
69
+ if (entry.expiresAt === -1)
70
+ return -1;
71
+ const remaining = entry.expiresAt - Date.now();
72
+ return remaining > 0 ? Math.ceil(remaining / 1000) : -1;
73
+ }
74
+ clean() {
75
+ const sizeBefore = this._store.size;
76
+ this._store.clear();
77
+ return sizeBefore;
78
+ }
79
+ _startCleanup() {
80
+ if (this._cleanupTimer)
81
+ return;
82
+ this._cleanupTimer = setInterval(() => {
83
+ this._removeExpiredEntries();
84
+ }, this._cleanupInterval);
85
+ }
86
+ _removeExpiredEntries() {
87
+ const now = Date.now();
88
+ for (const [key, entry] of this._store.entries())
89
+ if (entry.expiresAt !== -1 && now > entry.expiresAt)
90
+ this._store.delete(key);
91
+ }
92
+ destroy() {
93
+ if (this._cleanupTimer) {
94
+ clearInterval(this._cleanupTimer);
95
+ this._cleanupTimer = null;
96
+ }
97
+ this._store.clear();
98
+ }
99
+ }
7
100
  export {
8
101
  MemoryStore
9
102
  };
103
+ export { MemoryStore };
@@ -20,100 +20,16 @@ export declare class MemoryStore implements KvStore {
20
20
  * Timer for cleanup operations.
21
21
  */
22
22
  private _cleanupTimer;
23
- /**
24
- * Creates instance and starts cleanup process.
25
- *
26
- * @param cleanupIntervalMs - Cleanup interval in milliseconds (default: 300000 ms / 5 minutes)
27
- */
28
23
  constructor(cleanupIntervalMs?: number);
29
- /**
30
- * Retrieves a value from the store by key.
31
- * Automatically removes expired entries during retrieval.
32
- *
33
- * @template T - The expected type of the stored value
34
- *
35
- * @param key - The key to retrieve
36
- *
37
- * @returns The value associated with the key, or null if not found or expired
38
- */
39
24
  get<T = unknown>(key: string): T | null;
40
- /**
41
- * Stores a value in memory with optional TTL.
42
- *
43
- * @template T - The type of the value being stored
44
- *
45
- * @param key - The key to store the value under
46
- * @param value - The value to store
47
- * @param ttlSec - Time to live in seconds (optional)
48
- */
49
25
  set<T = unknown>(key: string, value: T, ttlSec?: number): void;
50
- /**
51
- * Increments a numeric value stored at key by the specified amount.
52
- * If the key does not exist, it is set to 0 before performing the operation.
53
- * Preserves existing TTL when incrementing.
54
- *
55
- * @param key - The key containing the numeric value
56
- * @param amount - The amount to increment by (default: 1)
57
- *
58
- * @throws ({@link BaseError}) - When the value is not a valid integer
59
- *
60
- * @returns The value after incrementing
61
- */
62
26
  increment(key: string, amount?: number): number;
63
- /**
64
- * Decrements a numeric value stored at key by the specified amount.
65
- * If the key does not exist, it is set to 0 before performing the operation.
66
- * Preserves existing TTL when decrementing.
67
- *
68
- * @param key - The key containing the numeric value
69
- * @param amount - The amount to decrement by (default: 1)
70
- *
71
- * @throws ({@link BaseError}) - When the value is not a valid integer
72
- *
73
- * @returns The value after decrementing
74
- */
75
27
  decrement(key: string, amount?: number): number;
76
- /**
77
- * Deletes a key from the store.
78
- *
79
- * @param key - The key to delete
80
- *
81
- * @returns True if the key was deleted, false if it did not exist
82
- */
83
28
  del(key: string): boolean;
84
- /**
85
- * Sets an expiration time for a key.
86
- *
87
- * @param key - The key to set expiration for
88
- * @param ttlSec - Time to live in seconds
89
- *
90
- * @returns True if the expiration was set, false if the key does not exist
91
- */
92
29
  expire(key: string, ttlSec: number): boolean;
93
- /**
94
- * Gets the remaining time to live for a key.
95
- *
96
- * @param key - The key to check
97
- *
98
- * @returns Time to live in seconds, -1 if key has no expiration or does not exist
99
- */
100
30
  ttl(key: string): number;
101
- /**
102
- * Removes all keys from the store.
103
- *
104
- * @returns The number of keys that were deleted
105
- */
106
31
  clean(): number;
107
- /**
108
- * Starts the cleanup process for expired entries.
109
- */
110
32
  private _startCleanup;
111
- /**
112
- * Removes expired entries from the store.
113
- */
114
33
  private _removeExpiredEntries;
115
- /**
116
- * Stops the cleanup process and clears resources.
117
- */
118
34
  destroy(): void;
119
35
  }
@@ -2,11 +2,11 @@ export interface KvStore {
2
2
  /**
3
3
  * Connect to the store.
4
4
  */
5
- connect?(): Promise<void>;
5
+ connect?(): Promise<void> | void;
6
6
  /**
7
7
  * Close the connection to the store.
8
8
  */
9
- close?(): Promise<void>;
9
+ close?(): Promise<void> | void;
10
10
  /**
11
11
  * Get the value associated with a key.
12
12
  *
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  LOGGER_ERROR_KEYS
4
- } from "../../../chunk-b96fm9ph.js";
4
+ } from "../../../chunk-rz5p4j3p.js";
5
5
  export {
6
6
  LOGGER_ERROR_KEYS
7
7
  };
@@ -1,6 +1,9 @@
1
1
  export declare const LOGGER_ERROR_KEYS: {
2
- readonly NO_SINK_ADDED: "mrx-core.logger.error.no_sink_added";
2
+ readonly BEFORE_EXIT_CLOSE_ERROR: "mrx-core.logger.error.before_exit_close_error";
3
+ readonly BEFORE_EXIT_FLUSH_ERROR: "mrx-core.logger.error.before_exit_flush_error";
4
+ readonly NO_SINKS_PROVIDED: "mrx-core.logger.error.no_sinks_provided";
5
+ readonly REGISTER_SINK_ERROR: "mrx-core.logger.error.register_sink_error";
3
6
  readonly SINK_ALREADY_ADDED: "mrx-core.logger.error.sink_already_added";
4
- readonly SINK_ERROR: "mrx-core.logger.error.sink_error";
5
- readonly SINK_NOT_FOUND: "mrx-core.logger.error.sink_not_found";
7
+ readonly SINK_CLOSE_ERROR: "mrx-core.logger.error.sink_close_error";
8
+ readonly SINK_LOG_ERROR: "mrx-core.logger.error.sink_log_error";
6
9
  };
@@ -1,11 +1,20 @@
1
1
  import type { BaseError } from '../../../errors/base-error';
2
2
  export interface LoggerEvent {
3
- error: [
3
+ onBeforeExitError: [BaseError<{
4
+ error: Error;
5
+ }>];
6
+ registerSinkError: [
4
7
  BaseError<{
5
8
  sinkName: string;
6
- object: unknown;
7
9
  error: Error;
8
10
  }>
9
11
  ];
10
- end: [];
12
+ sinkError: [
13
+ BaseError<{
14
+ sinkName: string;
15
+ object?: unknown;
16
+ error: Error;
17
+ }>
18
+ ];
19
+ drained: [];
11
20
  }
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  LOGGER_ERROR_KEYS
4
- } from "../../chunk-b96fm9ph.js";
4
+ } from "../../chunk-rz5p4j3p.js";
5
5
  import {
6
6
  TypedEventEmitter
7
7
  } from "../../chunk-mvrxngm7.js";
@@ -10,110 +10,202 @@ import {
10
10
  } from "../../chunk-9cgzhc50.js";
11
11
 
12
12
  // source/modules/logger/logger.ts
13
- import { once } from "events";
14
- import { Transform } from "stream";
15
13
  class Logger extends TypedEventEmitter {
16
14
  _sinks;
17
- _logStream;
18
- _pendingLogs = [];
15
+ _sinkKeys = [];
16
+ _worker;
19
17
  _maxPendingLogs;
18
+ _maxMessagesInFlight;
19
+ _batchSize;
20
+ _batchTimeout;
21
+ _autoEnd;
22
+ _flushOnBeforeExit;
23
+ _pendingLogs = [];
24
+ _messagesInFlight = 0;
25
+ _batchTimer = null;
20
26
  _isWriting = false;
21
- constructor(sinks = {}, maxPendingLogs = 1e4) {
27
+ _flushResolvers = [];
28
+ _closeResolver = null;
29
+ _backpressureResolver = null;
30
+ _handleExit = () => {
31
+ this._worker.terminate();
32
+ };
33
+ _handleWorkerClose = () => {
34
+ process.off("beforeExit", this._handleBeforeExit);
35
+ process.off("exit", this._handleExit);
36
+ };
37
+ constructor(options) {
22
38
  super();
23
- this._sinks = sinks;
39
+ const {
40
+ autoEnd = true,
41
+ batchSize = 50,
42
+ batchTimeout = 0.1,
43
+ flushOnBeforeExit = true,
44
+ maxMessagesInFlight = 100,
45
+ maxPendingLogs = 1e4
46
+ } = options ?? {};
47
+ this._sinks = {};
24
48
  this._maxPendingLogs = maxPendingLogs;
25
- this._logStream = new Transform({
26
- objectMode: true,
27
- transform: (chunk, _, callback) => {
28
- this._executeStrategies(chunk.level, new Date(chunk.date), chunk.object, chunk.sinksNames).then(() => callback()).catch((error) => {
29
- this.emit("error", error);
30
- callback();
31
- });
32
- }
33
- });
34
- }
35
- registerSink(name, sink) {
36
- if (this._sinks[name])
37
- throw new BaseError(LOGGER_ERROR_KEYS.SINK_ALREADY_ADDED, { sinkName: name });
38
- return new Logger({
39
- ...this._sinks,
40
- [name]: sink
41
- }, this._maxPendingLogs);
42
- }
43
- unregisterSink(name) {
44
- if (!(name in this._sinks))
45
- throw new BaseError(LOGGER_ERROR_KEYS.SINK_NOT_FOUND, { sinkName: name });
46
- const { [name]: _, ...rest } = this._sinks;
47
- return new Logger(rest, this._maxPendingLogs);
48
- }
49
- registerSinks(sinks) {
50
- return sinks.reduce((logger, [name, sink]) => logger.registerSink(name, sink), this);
49
+ this._maxMessagesInFlight = maxMessagesInFlight;
50
+ this._batchSize = batchSize;
51
+ this._batchTimeout = batchTimeout;
52
+ this._autoEnd = autoEnd;
53
+ this._flushOnBeforeExit = flushOnBeforeExit;
54
+ this._worker = new Worker(new URL("worker-logger.ts", import.meta.url).href, { type: "module" });
55
+ this._setupWorkerMessages();
56
+ if (this._autoEnd)
57
+ this._setupAutoEnd();
51
58
  }
52
- unregisterSinks(names) {
53
- let logger = this;
54
- for (const name of names)
55
- logger = logger.unregisterSink(name);
56
- return logger;
57
- }
58
- clearSinks() {
59
- return new Logger({}, this._maxPendingLogs);
59
+ registerSink(sinkName, sinkConstructor, ...sinkArgs) {
60
+ if (this._sinks[sinkName])
61
+ throw new Error(LOGGER_ERROR_KEYS.SINK_ALREADY_ADDED);
62
+ this._worker.postMessage({
63
+ type: "REGISTER_SINK",
64
+ sinkName,
65
+ sinkClassName: sinkConstructor.name,
66
+ sinkClassString: sinkConstructor.toString(),
67
+ sinkArgs
68
+ });
69
+ this._sinks[sinkName] = sinkConstructor;
70
+ this._sinkKeys.push(sinkName);
71
+ return this;
60
72
  }
61
- error(object, sinksNames) {
62
- this._out("ERROR", object, sinksNames);
73
+ error(object, sinkNames) {
74
+ this._enqueue("ERROR", object, sinkNames);
63
75
  }
64
- warn(object, sinksNames) {
65
- this._out("WARN", object, sinksNames);
76
+ warn(object, sinkNames) {
77
+ this._enqueue("WARN", object, sinkNames);
66
78
  }
67
- info(object, sinksNames) {
68
- this._out("INFO", object, sinksNames);
79
+ info(object, sinkNames) {
80
+ this._enqueue("INFO", object, sinkNames);
69
81
  }
70
- debug(object, sinksNames) {
71
- this._out("DEBUG", object, sinksNames);
82
+ debug(object, sinkNames) {
83
+ this._enqueue("DEBUG", object, sinkNames);
72
84
  }
73
- log(object, sinksNames) {
74
- this._out("LOG", object, sinksNames);
85
+ log(object, sinkNames = Object.keys(this._sinks)) {
86
+ this._enqueue("LOG", object, sinkNames);
75
87
  }
76
- async _executeStrategies(level, date, object, sinksNames) {
77
- await Promise.all(sinksNames.map(async (name) => {
78
- try {
79
- await this._sinks[name]?.log(level, date, object);
80
- } catch (error) {
81
- throw new BaseError(LOGGER_ERROR_KEYS.SINK_ERROR, { sinkName: name, object, error });
88
+ async flush() {
89
+ if (this._pendingLogs.length === 0 && this._messagesInFlight === 0)
90
+ return;
91
+ return new Promise((resolve) => {
92
+ this._flushResolvers.push(resolve);
93
+ if (!this._isWriting && this._pendingLogs.length > 0) {
94
+ this._isWriting = true;
95
+ this._processPendingLogs();
82
96
  }
83
- }));
97
+ });
84
98
  }
85
- _out(level, object, sinksNames) {
86
- const sinkKeys = Object.keys(this._sinks);
87
- if (sinkKeys.length === 0)
88
- throw new BaseError(LOGGER_ERROR_KEYS.NO_SINK_ADDED, { level, object });
99
+ async close() {
100
+ await this.flush();
101
+ return new Promise((resolve) => {
102
+ this._closeResolver = resolve;
103
+ this._worker.postMessage({ type: "CLOSE" });
104
+ });
105
+ }
106
+ _enqueue(level, object, sinkNames) {
107
+ if (this._sinkKeys.length === 0)
108
+ throw new BaseError(LOGGER_ERROR_KEYS.NO_SINKS_PROVIDED, { level, object });
89
109
  if (this._pendingLogs.length >= this._maxPendingLogs)
90
110
  return;
91
- const log = {
92
- date: new Date().toISOString(),
111
+ this._pendingLogs.push({
112
+ sinkNames: sinkNames ?? this._sinkKeys,
93
113
  level,
94
- object,
95
- sinksNames: sinksNames ? sinksNames : sinkKeys
96
- };
97
- this._pendingLogs.push(log);
98
- if (!this._isWriting) {
99
- this._isWriting = true;
100
- setImmediate(() => {
101
- this._writeLog();
102
- });
114
+ timestamp: Date.now(),
115
+ object
116
+ });
117
+ if (this._pendingLogs.length >= this._batchSize) {
118
+ if (this._batchTimer !== null) {
119
+ clearTimeout(this._batchTimer);
120
+ this._batchTimer = null;
121
+ }
122
+ this._triggerProcessing();
123
+ } else if (this._batchTimeout > 0 && this._batchTimer === null) {
124
+ this._batchTimer = setTimeout(() => {
125
+ this._batchTimer = null;
126
+ this._triggerProcessing();
127
+ }, this._batchTimeout);
103
128
  }
104
129
  }
105
- async _writeLog() {
130
+ _triggerProcessing() {
131
+ if (this._isWriting)
132
+ return;
133
+ this._isWriting = true;
134
+ this._processPendingLogs();
135
+ }
136
+ async _processPendingLogs() {
106
137
  while (this._pendingLogs.length > 0) {
107
- const pendingLog = this._pendingLogs.shift();
108
- if (!pendingLog)
109
- continue;
110
- const canWrite = this._logStream.write(pendingLog);
111
- if (!canWrite)
112
- await once(this._logStream, "drain");
138
+ if (this._messagesInFlight >= this._maxMessagesInFlight)
139
+ await new Promise((resolve) => {
140
+ this._backpressureResolver = resolve;
141
+ });
142
+ const batch = this._pendingLogs.splice(0, this._batchSize);
143
+ this._messagesInFlight++;
144
+ this._worker.postMessage({
145
+ type: "LOG_BATCH",
146
+ logs: batch
147
+ });
113
148
  }
114
149
  this._isWriting = false;
115
- this.emit("end");
150
+ this.emit("drained");
151
+ }
152
+ _releaseBatch() {
153
+ this._messagesInFlight--;
154
+ if (this._backpressureResolver !== null) {
155
+ this._backpressureResolver();
156
+ this._backpressureResolver = null;
157
+ }
158
+ }
159
+ _setupWorkerMessages() {
160
+ this._worker.addEventListener("message", (event) => {
161
+ switch (event.data.type) {
162
+ case "BATCH_COMPLETE":
163
+ this._releaseBatch();
164
+ if (this._messagesInFlight === 0 && this._pendingLogs.length === 0 && this._flushResolvers.length > 0) {
165
+ for (const resolve of this._flushResolvers)
166
+ resolve();
167
+ this._flushResolvers.length = 0;
168
+ }
169
+ break;
170
+ case "SINK_LOG_ERROR":
171
+ this.emit("sinkError", new BaseError(LOGGER_ERROR_KEYS.SINK_LOG_ERROR, event.data));
172
+ this._releaseBatch();
173
+ break;
174
+ case "SINK_CLOSE_ERROR":
175
+ this.emit("sinkError", new BaseError(LOGGER_ERROR_KEYS.SINK_CLOSE_ERROR, event.data));
176
+ break;
177
+ case "REGISTER_SINK_ERROR":
178
+ this.emit("registerSinkError", new BaseError(LOGGER_ERROR_KEYS.REGISTER_SINK_ERROR, event.data));
179
+ break;
180
+ case "CLOSE_COMPLETE":
181
+ this._worker.terminate();
182
+ if (this._closeResolver) {
183
+ this._closeResolver();
184
+ this._closeResolver = null;
185
+ }
186
+ break;
187
+ }
188
+ });
116
189
  }
190
+ _setupAutoEnd() {
191
+ process.on("beforeExit", this._handleBeforeExit);
192
+ process.on("exit", this._handleExit);
193
+ this._worker.addEventListener("close", this._handleWorkerClose);
194
+ }
195
+ _handleBeforeExit = () => {
196
+ if (this._flushOnBeforeExit)
197
+ this.flush().then(() => this.close()).catch((error) => {
198
+ this.emit("onBeforeExitError", new BaseError(LOGGER_ERROR_KEYS.BEFORE_EXIT_FLUSH_ERROR, {
199
+ error: error instanceof Error ? error : new Error("Unknown error during logger flush on beforeExit")
200
+ }));
201
+ });
202
+ else
203
+ this.close().catch((error) => {
204
+ this.emit("onBeforeExitError", new BaseError(LOGGER_ERROR_KEYS.BEFORE_EXIT_CLOSE_ERROR, {
205
+ error: error instanceof Error ? error : new Error("Unknown error during logger close on beforeExit")
206
+ }));
207
+ });
208
+ };
117
209
  }
118
210
  export {
119
211
  Logger