@mrxsys/mrx-core 2.11.0-2-and-276-20251029 → 2.11.0-4-and-276-20251029
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-0d0zd2yg.js +8 -0
- package/dist/chunk-12qzn7jw.js +7 -0
- package/dist/chunk-441xs5k1.js +53 -0
- package/dist/chunk-4v86f7gp.js +59 -0
- package/dist/chunk-6w9ja96e.js +9 -0
- package/dist/chunk-7t524zqh.js +26 -0
- package/dist/chunk-8tffnbpn.js +7 -0
- package/dist/chunk-9cgzhc50.js +15 -0
- package/dist/chunk-9d3zvgp6.js +9 -0
- package/dist/chunk-9dzsj7f2.js +23 -0
- package/dist/chunk-9r5anep5.js +11 -0
- package/dist/chunk-afd82epa.js +201 -0
- package/dist/chunk-afyz8rg5.js +209 -0
- package/dist/chunk-dre2fgj0.js +7 -0
- package/dist/chunk-e30paw8a.js +101 -0
- package/dist/chunk-eeb7yskp.js +61 -0
- package/dist/chunk-fs3wm3p4.js +32 -0
- package/dist/chunk-grfyngq0.js +39 -0
- package/dist/chunk-gtn1kn0z.js +79 -0
- package/dist/chunk-jksb9ers.js +7 -0
- package/dist/chunk-m3grz32t.js +27 -0
- package/dist/chunk-mvrxngm7.js +41 -0
- package/dist/chunk-n0n14mf8.js +7 -0
- package/dist/chunk-p14h6jfs.js +365 -0
- package/dist/chunk-pjv1ekwr.js +284 -0
- package/dist/chunk-rz5p4j3p.js +13 -0
- package/dist/chunk-spnh9dzk.js +10 -0
- package/dist/chunk-sqts8vyk.js +60 -0
- package/dist/chunk-w7h898m3.js +14 -0
- package/dist/chunk-xhhj1gvj.js +9 -0
- package/dist/chunk-z0ct35ft.js +8 -0
- package/dist/errors/enums/index.js +7 -0
- package/dist/errors/index.js +12 -0
- package/dist/errors/utils/index.js +16 -0
- package/dist/errors/utils/is-nowarajs-error.ts.d.ts +2 -2
- package/dist/modules/data/enums/index.js +7 -0
- package/dist/modules/data/index.js +17 -0
- package/dist/modules/data/transformers/camel-case.d.ts +2 -2
- package/dist/modules/data/transformers/index.js +32 -0
- package/dist/modules/data/transformers/kebab-case.d.ts +2 -2
- package/dist/modules/data/transformers/pascal-case.d.ts +2 -2
- package/dist/modules/data/transformers/snake-case.d.ts +2 -2
- package/dist/modules/data/types/index.js +1 -0
- package/dist/modules/data/types/transform-object-keys.d.ts +4 -4
- package/dist/modules/database/enums/index.js +9 -0
- package/dist/modules/database/events/index.js +1 -0
- package/dist/modules/database/events/mssql-event-map.d.ts +1 -1
- package/dist/modules/database/events/table-event-map.d.ts +1 -1
- package/dist/modules/database/index.js +16 -0
- package/dist/modules/database/mssql.d.ts +2 -2
- package/dist/modules/database/table.d.ts +2 -2
- package/dist/modules/database/types/index.js +1 -0
- package/dist/modules/elysia/cache/cache.d.ts +1 -1
- package/dist/modules/elysia/cache/index.js +90 -0
- package/dist/modules/elysia/cache/types/index.js +1 -0
- package/dist/modules/elysia/crud/crud.d.ts +2 -2
- package/dist/modules/elysia/crud/enums/index.js +7 -0
- package/dist/modules/elysia/crud/index.js +153 -0
- package/dist/modules/elysia/crud/operations/count.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/delete.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/deleteOne.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/find.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/findOne.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/index.js +34 -0
- package/dist/modules/elysia/crud/operations/insert.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/update.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/updateOne.d.ts +3 -3
- package/dist/modules/elysia/crud/operations/utils/get-db-injection.d.ts +1 -1
- package/dist/modules/elysia/crud/types/crud-options.d.ts +1 -1
- package/dist/modules/elysia/crud/types/crud-schema-models-type.d.ts +9 -9
- package/dist/modules/elysia/crud/types/delete-schema.d.ts +2 -2
- package/dist/modules/elysia/crud/types/find-schema.d.ts +3 -3
- package/dist/modules/elysia/crud/types/index.js +1 -0
- package/dist/modules/elysia/crud/types/insert-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/types/properties-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/types/response-200-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/types/update-schema.d.ts +2 -2
- package/dist/modules/elysia/crud/utils/create-adaptive-where-clause-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-count-response-200-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-count-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-delete-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-filters-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-find-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-id-param-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-insert-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-order-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-properties-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-q-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-response-200-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-selected-fields-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-update-one-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/create-update-schema.d.ts +1 -1
- package/dist/modules/elysia/crud/utils/index.js +41 -0
- package/dist/modules/elysia/db-resolver/db-resolver.d.ts +2 -2
- package/dist/modules/elysia/db-resolver/enums/index.js +7 -0
- package/dist/modules/elysia/db-resolver/index.js +18 -0
- package/dist/modules/elysia/error/enums/index.js +7 -0
- package/dist/modules/elysia/error/error.d.ts +5 -0
- package/dist/modules/elysia/error/index.d.ts +1 -1
- package/dist/modules/elysia/error/index.js +67 -0
- package/dist/modules/elysia/microservice/enums/index.js +7 -0
- package/dist/modules/elysia/microservice/index.js +100 -0
- package/dist/modules/elysia/rate-limit/enums/index.js +7 -0
- package/dist/modules/elysia/rate-limit/index.js +81 -0
- package/dist/modules/elysia/rate-limit/rate-limit.d.ts +1 -1
- package/dist/modules/elysia/rate-limit/types/index.js +1 -0
- package/dist/modules/jwt/enums/index.js +11 -0
- package/dist/modules/jwt/index.js +51 -0
- package/dist/modules/jwt/utils/index.js +9 -0
- package/dist/modules/kv-store/bun-redis/bun-redis-store.d.ts +1 -1
- package/dist/modules/kv-store/bun-redis/index.js +84 -0
- package/dist/modules/kv-store/enums/index.js +7 -0
- package/dist/modules/kv-store/ioredis/index.js +86 -0
- package/dist/modules/kv-store/ioredis/ioredis-store.d.ts +1 -1
- package/dist/modules/kv-store/memory/index.js +9 -0
- package/dist/modules/kv-store/memory/memory-store.d.ts +1 -1
- package/dist/modules/kv-store/types/index.js +1 -0
- package/dist/modules/logger/enums/index.js +7 -0
- package/dist/modules/logger/events/index.js +1 -0
- package/dist/modules/logger/events/logger-events.d.ts +1 -1
- package/dist/modules/logger/index.js +208 -0
- package/dist/modules/logger/logger.d.ts +1 -1
- package/dist/modules/logger/sinks/console-logger.d.ts +2 -2
- package/dist/modules/logger/sinks/devnull-logger.d.ts +1 -1
- package/dist/modules/logger/sinks/file-logger/file-logger.d.ts +2 -2
- package/dist/modules/logger/sinks/index.js +66 -0
- package/dist/modules/logger/types/index.js +1 -0
- package/dist/modules/mailer/enums/index.js +7 -0
- package/dist/modules/mailer/index.js +55 -0
- package/dist/modules/mailer/types/index.js +1 -0
- package/dist/modules/repository/index.js +12 -0
- package/dist/modules/repository/repository.d.ts +2 -2
- package/dist/modules/repository/types/index.js +1 -0
- package/dist/modules/repository/types/query-options.d.ts +1 -1
- package/dist/modules/singleton-manager/enums/index.js +7 -0
- package/dist/modules/singleton-manager/index.js +9 -0
- package/dist/modules/totp/enums/index.js +7 -0
- package/dist/modules/totp/index.js +104 -0
- package/dist/modules/totp/types/index.js +1 -0
- package/dist/modules/totp/utils/index.js +76 -0
- package/dist/modules/typed-event-emitter/index.js +7 -0
- package/dist/modules/typed-event-emitter/types/index.js +1 -0
- package/dist/shared/enums/index.js +7 -0
- package/dist/shared/types/index.js +1 -0
- package/dist/shared/utils/flatten.d.ts +1 -1
- package/dist/shared/utils/index.js +30 -0
- package/package.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
RATE_LIMIT_ERROR_KEYS
|
|
4
|
+
} from "../../../chunk-dre2fgj0.js";
|
|
5
|
+
import {
|
|
6
|
+
MemoryStore
|
|
7
|
+
} from "../../../chunk-e30paw8a.js";
|
|
8
|
+
import"../../../chunk-xhhj1gvj.js";
|
|
9
|
+
import {
|
|
10
|
+
HttpError
|
|
11
|
+
} from "../../../chunk-7t524zqh.js";
|
|
12
|
+
import"../../../chunk-sqts8vyk.js";
|
|
13
|
+
import"../../../chunk-9cgzhc50.js";
|
|
14
|
+
|
|
15
|
+
// source/modules/elysia/rate-limit/rate-limit.ts
|
|
16
|
+
import { Elysia } from "elysia";
|
|
17
|
+
var rateLimit = (store) => {
|
|
18
|
+
const restrictedRoutes = new Map;
|
|
19
|
+
store = store || new MemoryStore;
|
|
20
|
+
const rateLimitCheck = async (key, limit, window, set) => {
|
|
21
|
+
if (set.headers["X-RateLimit-Limit"])
|
|
22
|
+
return;
|
|
23
|
+
let count = await store.get(key) ?? 0;
|
|
24
|
+
if (count === 0) {
|
|
25
|
+
await store.set(key, 1, window);
|
|
26
|
+
count = 1;
|
|
27
|
+
} else {
|
|
28
|
+
count = await store.increment(key);
|
|
29
|
+
}
|
|
30
|
+
const remaining = Math.max(0, limit - count);
|
|
31
|
+
const resetTime = await store.ttl(key);
|
|
32
|
+
set.headers = {
|
|
33
|
+
"X-RateLimit-Limit": limit.toString(),
|
|
34
|
+
"X-RateLimit-Remaining": remaining.toString(),
|
|
35
|
+
"X-RateLimit-Reset": resetTime.toString()
|
|
36
|
+
};
|
|
37
|
+
if (count > limit) {
|
|
38
|
+
set.status = 429;
|
|
39
|
+
throw new HttpError(RATE_LIMIT_ERROR_KEYS.RATE_LIMIT_EXCEEDED, "TOO_MANY_REQUESTS", {
|
|
40
|
+
limit,
|
|
41
|
+
window,
|
|
42
|
+
remaining: 0,
|
|
43
|
+
reset: resetTime
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return new Elysia({
|
|
48
|
+
name: "rateLimit",
|
|
49
|
+
seed: {
|
|
50
|
+
store
|
|
51
|
+
}
|
|
52
|
+
}).macro({
|
|
53
|
+
rateLimit: ({ limit, window }) => ({
|
|
54
|
+
transform: ({ request }) => {
|
|
55
|
+
const route = `${request.method}:${new URL(request.url).pathname}`;
|
|
56
|
+
if (!restrictedRoutes.has(route)) {
|
|
57
|
+
restrictedRoutes.set(route, { limit, window });
|
|
58
|
+
} else if (restrictedRoutes.has(route)) {
|
|
59
|
+
const existing = restrictedRoutes.get(route);
|
|
60
|
+
if (limit != existing.limit || window != existing.window)
|
|
61
|
+
restrictedRoutes.set(route, {
|
|
62
|
+
limit,
|
|
63
|
+
window
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
beforeHandle: async ({ set, request, server }) => {
|
|
68
|
+
const route = `${request.method}:${new URL(request.url).pathname}`;
|
|
69
|
+
if (restrictedRoutes.has(route)) {
|
|
70
|
+
const { limit: limit2, window: window2 } = restrictedRoutes.get(route);
|
|
71
|
+
const ip = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || server?.requestIP(request)?.address || "127.0.0.1";
|
|
72
|
+
const key = `ratelimit:${route}:${ip}`;
|
|
73
|
+
await rateLimitCheck(key, limit2, window2, set);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}).as("global");
|
|
78
|
+
};
|
|
79
|
+
export {
|
|
80
|
+
rateLimit
|
|
81
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { KvStore } from '
|
|
1
|
+
import type { KvStore } from '../../../modules/kv-store/types/kv-store';
|
|
2
2
|
import { Elysia, type HTTPHeaders, type StatusMap } from 'elysia';
|
|
3
3
|
import type { RateLimitOptions } from './types/rate-limit-options';
|
|
4
4
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
JWT_ERROR_KEYS
|
|
4
|
+
} from "../../chunk-9d3zvgp6.js";
|
|
5
|
+
import {
|
|
6
|
+
parseHumanTimeToSeconds
|
|
7
|
+
} from "../../chunk-eeb7yskp.js";
|
|
8
|
+
import"../../chunk-12qzn7jw.js";
|
|
9
|
+
import {
|
|
10
|
+
HttpError
|
|
11
|
+
} from "../../chunk-7t524zqh.js";
|
|
12
|
+
import"../../chunk-sqts8vyk.js";
|
|
13
|
+
import"../../chunk-9cgzhc50.js";
|
|
14
|
+
|
|
15
|
+
// source/modules/jwt/jwt.ts
|
|
16
|
+
import {
|
|
17
|
+
SignJWT,
|
|
18
|
+
jwtVerify
|
|
19
|
+
} from "jose";
|
|
20
|
+
var signJWT = (secret, payload, expiration = Math.floor(Date.now() / 1000) + 60 * 15) => {
|
|
21
|
+
const exp = expiration instanceof Date ? Math.floor(expiration.getTime() / 1000) : typeof expiration === "number" ? expiration : Math.floor(Date.now() / 1000) + parseHumanTimeToSeconds(expiration);
|
|
22
|
+
if (exp <= Math.floor(Date.now() / 1000))
|
|
23
|
+
throw new HttpError(JWT_ERROR_KEYS.JWT_EXPIRATION_PASSED, "BAD_REQUEST");
|
|
24
|
+
const finalPayload = {
|
|
25
|
+
iss: "Core-Issuer",
|
|
26
|
+
sub: "",
|
|
27
|
+
aud: ["Core-Audience"],
|
|
28
|
+
jti: Bun.randomUUIDv7(),
|
|
29
|
+
nbf: Math.floor(Date.now() / 1000),
|
|
30
|
+
iat: Math.floor(Date.now() / 1000),
|
|
31
|
+
exp,
|
|
32
|
+
...payload
|
|
33
|
+
};
|
|
34
|
+
try {
|
|
35
|
+
const jwt = new SignJWT(finalPayload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuer(finalPayload.iss).setSubject(finalPayload.sub).setAudience(finalPayload.aud).setJti(finalPayload.jti).setNotBefore(finalPayload.nbf).setIssuedAt(finalPayload.iat).setExpirationTime(expiration).sign(new TextEncoder().encode(secret));
|
|
36
|
+
return jwt;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new HttpError(JWT_ERROR_KEYS.JWT_SIGN_ERROR, "INTERNAL_SERVER_ERROR", error);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var verifyJWT = async (token, secret) => {
|
|
42
|
+
try {
|
|
43
|
+
return await jwtVerify(token, new TextEncoder().encode(secret));
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
verifyJWT,
|
|
50
|
+
signJWT
|
|
51
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
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/bun-redis/bun-redis-store.ts
|
|
10
|
+
var {RedisClient } = globalThis.Bun;
|
|
11
|
+
class BunRedisStore {
|
|
12
|
+
_client;
|
|
13
|
+
constructor(url, options) {
|
|
14
|
+
this._client = new RedisClient(url, options);
|
|
15
|
+
}
|
|
16
|
+
async connect() {
|
|
17
|
+
try {
|
|
18
|
+
await this._client.connect();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.CONNECTION_FAILED, e);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
close() {
|
|
24
|
+
try {
|
|
25
|
+
this._client.close();
|
|
26
|
+
} catch (e) {
|
|
27
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.CLOSING_CONNECTION_FAILED, e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async get(key) {
|
|
31
|
+
const value = await this._client.get(key);
|
|
32
|
+
if (value === null)
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(value);
|
|
36
|
+
} catch {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async set(key, value, ttlSec) {
|
|
41
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
42
|
+
if (ttlSec)
|
|
43
|
+
await this._client.set(key, serialized, "EX", ttlSec);
|
|
44
|
+
else
|
|
45
|
+
await this._client.set(key, serialized);
|
|
46
|
+
}
|
|
47
|
+
async increment(key, amount) {
|
|
48
|
+
try {
|
|
49
|
+
const number = await this._client.incrby(key, amount ?? 1);
|
|
50
|
+
return number;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async decrement(key, amount) {
|
|
56
|
+
try {
|
|
57
|
+
const number = await this._client.decrby(key, amount ?? 1);
|
|
58
|
+
return number;
|
|
59
|
+
} catch (e) {
|
|
60
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async del(key) {
|
|
64
|
+
const res = await this._client.del(key);
|
|
65
|
+
return res === 1;
|
|
66
|
+
}
|
|
67
|
+
async expire(key, ttlSec) {
|
|
68
|
+
const res = await this._client.expire(key, ttlSec);
|
|
69
|
+
return res === 1;
|
|
70
|
+
}
|
|
71
|
+
async ttl(key) {
|
|
72
|
+
const res = await this._client.ttl(key);
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
async clean() {
|
|
76
|
+
const keys = await this._client.keys("*");
|
|
77
|
+
if (keys.length === 0)
|
|
78
|
+
return 0;
|
|
79
|
+
return this._client.del(...keys);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
BunRedisStore
|
|
84
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
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/ioredis/ioredis-store.ts
|
|
10
|
+
import { Redis } from "ioredis";
|
|
11
|
+
class IoRedisStore {
|
|
12
|
+
_client;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this._client = new Redis({
|
|
15
|
+
...options,
|
|
16
|
+
lazyConnect: true
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async connect() {
|
|
20
|
+
try {
|
|
21
|
+
await this._client.connect();
|
|
22
|
+
} catch (e) {
|
|
23
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.CONNECTION_FAILED, e);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async close() {
|
|
27
|
+
try {
|
|
28
|
+
await this._client.quit();
|
|
29
|
+
} catch (e) {
|
|
30
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.CLOSING_CONNECTION_FAILED, e);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async get(key) {
|
|
34
|
+
const value = await this._client.get(key);
|
|
35
|
+
if (value === null)
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(value);
|
|
39
|
+
} catch {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async set(key, value, ttlSec) {
|
|
44
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
45
|
+
if (ttlSec)
|
|
46
|
+
await this._client.setex(key, ttlSec, serialized);
|
|
47
|
+
else
|
|
48
|
+
await this._client.set(key, serialized);
|
|
49
|
+
}
|
|
50
|
+
async increment(key, amount = 1) {
|
|
51
|
+
try {
|
|
52
|
+
const number = await this._client.incrby(key, amount);
|
|
53
|
+
return number;
|
|
54
|
+
} catch (e) {
|
|
55
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async decrement(key, amount = 1) {
|
|
59
|
+
try {
|
|
60
|
+
const number = await this._client.decrby(key, amount);
|
|
61
|
+
return number;
|
|
62
|
+
} catch (e) {
|
|
63
|
+
throw new BaseError(KV_STORE_ERROR_KEYS.NOT_INTEGER, e);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async del(key) {
|
|
67
|
+
const result = await this._client.del(key);
|
|
68
|
+
return result === 1;
|
|
69
|
+
}
|
|
70
|
+
async expire(key, ttlSec) {
|
|
71
|
+
const result = await this._client.expire(key, ttlSec);
|
|
72
|
+
return result === 1;
|
|
73
|
+
}
|
|
74
|
+
ttl(key) {
|
|
75
|
+
return this._client.ttl(key);
|
|
76
|
+
}
|
|
77
|
+
async clean() {
|
|
78
|
+
const keys = await this._client.keys("*");
|
|
79
|
+
if (keys.length === 0)
|
|
80
|
+
return 0;
|
|
81
|
+
return this._client.del(...keys);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
IoRedisStore
|
|
86
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
LOGGER_ERROR_KEYS
|
|
4
|
+
} from "../../chunk-rz5p4j3p.js";
|
|
5
|
+
import {
|
|
6
|
+
TypedEventEmitter
|
|
7
|
+
} from "../../chunk-mvrxngm7.js";
|
|
8
|
+
import {
|
|
9
|
+
BaseError
|
|
10
|
+
} from "../../chunk-9cgzhc50.js";
|
|
11
|
+
|
|
12
|
+
// source/modules/logger/logger.ts
|
|
13
|
+
class Logger extends TypedEventEmitter {
|
|
14
|
+
_sinks;
|
|
15
|
+
_sinkKeys = [];
|
|
16
|
+
_worker;
|
|
17
|
+
_maxPendingLogs;
|
|
18
|
+
_maxMessagesInFlight;
|
|
19
|
+
_batchSize;
|
|
20
|
+
_batchTimeout;
|
|
21
|
+
_autoEnd;
|
|
22
|
+
_flushOnBeforeExit;
|
|
23
|
+
_pendingLogs = [];
|
|
24
|
+
_messagesInFlight = 0;
|
|
25
|
+
_batchTimer = null;
|
|
26
|
+
_isWriting = false;
|
|
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) {
|
|
38
|
+
super();
|
|
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 = {};
|
|
48
|
+
this._maxPendingLogs = maxPendingLogs;
|
|
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();
|
|
58
|
+
}
|
|
59
|
+
registerSink(sinkName, sinkConstructor, ...sinkArgs) {
|
|
60
|
+
if (this._sinks[sinkName])
|
|
61
|
+
throw new BaseError(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;
|
|
72
|
+
}
|
|
73
|
+
error(object, sinkNames = this._sinkKeys) {
|
|
74
|
+
this._enqueue("ERROR", object, sinkNames);
|
|
75
|
+
}
|
|
76
|
+
warn(object, sinkNames = this._sinkKeys) {
|
|
77
|
+
this._enqueue("WARN", object, sinkNames);
|
|
78
|
+
}
|
|
79
|
+
info(object, sinkNames = this._sinkKeys) {
|
|
80
|
+
this._enqueue("INFO", object, sinkNames);
|
|
81
|
+
}
|
|
82
|
+
debug(object, sinkNames = this._sinkKeys) {
|
|
83
|
+
this._enqueue("DEBUG", object, sinkNames);
|
|
84
|
+
}
|
|
85
|
+
log(object, sinkNames = this._sinkKeys) {
|
|
86
|
+
this._enqueue("LOG", object, sinkNames);
|
|
87
|
+
}
|
|
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();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
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 });
|
|
109
|
+
if (this._pendingLogs.length >= this._maxPendingLogs)
|
|
110
|
+
return;
|
|
111
|
+
this._pendingLogs.push({
|
|
112
|
+
sinkNames: sinkNames ?? this._sinkKeys,
|
|
113
|
+
level,
|
|
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);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
_triggerProcessing() {
|
|
131
|
+
if (this._isWriting)
|
|
132
|
+
return;
|
|
133
|
+
this._isWriting = true;
|
|
134
|
+
this._processPendingLogs();
|
|
135
|
+
}
|
|
136
|
+
async _processPendingLogs() {
|
|
137
|
+
while (this._pendingLogs.length > 0) {
|
|
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
|
+
});
|
|
148
|
+
}
|
|
149
|
+
this._isWriting = false;
|
|
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
|
+
});
|
|
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, { error }));
|
|
199
|
+
});
|
|
200
|
+
else
|
|
201
|
+
this.close().catch((error) => {
|
|
202
|
+
this.emit("onBeforeExitError", new BaseError(LOGGER_ERROR_KEYS.BEFORE_EXIT_CLOSE_ERROR, { error }));
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
export {
|
|
207
|
+
Logger
|
|
208
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypedEventEmitter } from '
|
|
1
|
+
import { TypedEventEmitter } from '../../modules/typed-event-emitter/typed-event-emitter';
|
|
2
2
|
import type { LoggerEvent } from './events/logger-events';
|
|
3
3
|
import type { LoggerOptions } from './types/logger-options';
|
|
4
4
|
import type { LoggerSink } from './types/logger-sink';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { LogLevels } from '
|
|
2
|
-
import type { LoggerSink } from '
|
|
1
|
+
import type { LogLevels } from '../../../modules/logger/types/log-levels';
|
|
2
|
+
import type { LoggerSink } from '../../../modules/logger/types/logger-sink';
|
|
3
3
|
/**
|
|
4
4
|
* ConsoleLoggerSink implements LoggerSink to provide logging functionality to the console.
|
|
5
5
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LoggerSink } from '
|
|
1
|
+
import type { LoggerSink } from '../../../modules/logger/types/logger-sink';
|
|
2
2
|
/**
|
|
3
3
|
* DevNullLoggerSink implements LoggerSink to discard all logs (like /dev/null).
|
|
4
4
|
* Useful for benchmarking the logger overhead without I/O.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { LogLevels } from '
|
|
2
|
-
import type { LoggerSink } from '
|
|
1
|
+
import type { LogLevels } from '../../../../modules/logger/types/log-levels';
|
|
2
|
+
import type { LoggerSink } from '../../../../modules/logger/types/logger-sink';
|
|
3
3
|
export interface FileLoggerConfig {
|
|
4
4
|
/**
|
|
5
5
|
* Path to the file to log to.
|