@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.
- package/dist/{chunk-fp8xg6kq.js → chunk-441xs5k1.js} +1 -1
- package/dist/{chunk-bdcsh435.js → chunk-4v86f7gp.js} +5 -5
- package/dist/{chunk-00s6t4tw.js → chunk-7t524zqh.js} +4 -4
- package/dist/{chunk-d1vp74n0.js → chunk-afd82epa.js} +2 -2
- package/dist/{chunk-v9kvw5x7.js → chunk-afyz8rg5.js} +2 -2
- package/dist/{chunk-6sfnrhfs.js → chunk-pjv1ekwr.js} +33 -1
- package/dist/chunk-rz5p4j3p.js +13 -0
- package/dist/{chunk-h9t48r9q.js → chunk-sqts8vyk.js} +16 -2
- package/dist/errors/enums/http-status-codes.d.ts +15 -1
- package/dist/errors/enums/index.d.ts +1 -1
- package/dist/errors/enums/index.js +3 -3
- package/dist/errors/http-error.d.ts +3 -3
- package/dist/errors/index.js +2 -2
- package/dist/errors/utils/index.js +2 -2
- package/dist/modules/database/enums/database-error-keys.d.ts +2 -2
- package/dist/modules/database/enums/index.js +1 -1
- package/dist/modules/database/index.js +5 -5
- package/dist/modules/elysia/cache/cache.d.ts +8 -14
- package/dist/modules/elysia/cache/index.js +66 -46
- package/dist/modules/elysia/cache/types/cache-item.d.ts +0 -1
- package/dist/modules/elysia/cache/types/cache-options.d.ts +2 -11
- package/dist/modules/elysia/crud/index.js +16 -16
- package/dist/modules/elysia/crud/operations/count.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/delete.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/deleteOne.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/find.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/findOne.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/index.js +7 -7
- package/dist/modules/elysia/crud/operations/insert.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/update.d.ts +1 -1
- package/dist/modules/elysia/crud/operations/updateOne.d.ts +1 -1
- package/dist/modules/elysia/db-resolver/db-resolver.d.ts +1 -1
- package/dist/modules/elysia/db-resolver/index.js +6 -6
- package/dist/modules/elysia/error/index.js +2 -2
- package/dist/modules/elysia/microservice/microservice.d.ts +12 -12
- package/dist/modules/elysia/rate-limit/index.js +53 -28
- package/dist/modules/elysia/rate-limit/rate-limit.d.ts +361 -32
- package/dist/modules/elysia/rate-limit/types/rate-limit-options.d.ts +0 -9
- package/dist/modules/jwt/index.js +2 -2
- package/dist/modules/kv-store/bun-redis/bun-redis-store.d.ts +25 -0
- package/dist/modules/kv-store/bun-redis/index.d.ts +1 -0
- package/dist/modules/kv-store/bun-redis/index.js +76 -0
- package/dist/modules/kv-store/ioredis/index.js +4 -10
- package/dist/modules/kv-store/ioredis/ioredis-store.d.ts +0 -82
- package/dist/modules/kv-store/memory/index.js +98 -4
- package/dist/modules/kv-store/memory/memory-store.d.ts +0 -84
- package/dist/modules/kv-store/types/kv-store.d.ts +2 -2
- package/dist/modules/logger/enums/index.js +1 -1
- package/dist/modules/logger/enums/logger-error-keys.d.ts +6 -3
- package/dist/modules/logger/events/logger-events.d.ts +12 -3
- package/dist/modules/logger/index.js +173 -81
- package/dist/modules/logger/logger.d.ts +115 -133
- package/dist/modules/logger/sinks/console-logger.d.ts +2 -16
- package/dist/modules/logger/sinks/devnull-logger.d.ts +8 -0
- package/dist/modules/logger/sinks/file-logger/enums/file-logger-error-keys.d.ts +3 -0
- package/dist/modules/logger/sinks/file-logger/file-logger.d.ts +25 -0
- package/dist/modules/logger/sinks/index.d.ts +4 -2
- package/dist/modules/logger/sinks/index.js +54 -31
- package/dist/modules/logger/types/index.d.ts +6 -6
- package/dist/modules/logger/types/log-levels.d.ts +1 -4
- package/dist/modules/logger/types/logger-options.d.ts +41 -0
- package/dist/modules/logger/types/logger-sink.d.ts +12 -3
- package/dist/modules/logger/types/sink-bodies-intersection.d.ts +2 -0
- package/dist/modules/logger/types/sink-body.d.ts +1 -1
- package/dist/modules/logger/types/sink-map.d.ts +1 -1
- package/dist/modules/repository/index.js +4 -4
- package/dist/modules/repository/types/query-options.d.ts +2 -2
- package/package.json +30 -25
- package/dist/chunk-b23dvm2d.js +0 -29
- package/dist/chunk-b96fm9ph.js +0 -10
- package/dist/chunk-e30paw8a.js +0 -101
- package/dist/modules/elysia/cache/utils/index.d.ts +0 -1
- package/dist/modules/elysia/cache/utils/index.js +0 -7
- package/dist/modules/logger/sinks/file-logger.d.ts +0 -25
- package/dist/modules/logger/types/bodies-intersection.d.ts +0 -2
- 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
|
-
|
|
4
|
-
} from "../../../chunk-
|
|
5
|
-
import
|
|
6
|
-
|
|
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,6 +1,9 @@
|
|
|
1
1
|
export declare const LOGGER_ERROR_KEYS: {
|
|
2
|
-
readonly
|
|
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
|
|
5
|
-
readonly
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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,
|
|
62
|
-
this.
|
|
73
|
+
error(object, sinkNames) {
|
|
74
|
+
this._enqueue("ERROR", object, sinkNames);
|
|
63
75
|
}
|
|
64
|
-
warn(object,
|
|
65
|
-
this.
|
|
76
|
+
warn(object, sinkNames) {
|
|
77
|
+
this._enqueue("WARN", object, sinkNames);
|
|
66
78
|
}
|
|
67
|
-
info(object,
|
|
68
|
-
this.
|
|
79
|
+
info(object, sinkNames) {
|
|
80
|
+
this._enqueue("INFO", object, sinkNames);
|
|
69
81
|
}
|
|
70
|
-
debug(object,
|
|
71
|
-
this.
|
|
82
|
+
debug(object, sinkNames) {
|
|
83
|
+
this._enqueue("DEBUG", object, sinkNames);
|
|
72
84
|
}
|
|
73
|
-
log(object,
|
|
74
|
-
this.
|
|
85
|
+
log(object, sinkNames = Object.keys(this._sinks)) {
|
|
86
|
+
this._enqueue("LOG", object, sinkNames);
|
|
75
87
|
}
|
|
76
|
-
async
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
92
|
-
|
|
111
|
+
this._pendingLogs.push({
|
|
112
|
+
sinkNames: sinkNames ?? this._sinkKeys,
|
|
93
113
|
level,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
};
|
|
97
|
-
this._pendingLogs.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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("
|
|
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
|