@mrxsys/mrx-core 2.11.0-1-and-269-20251003 → 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-dzfefxjq.js → chunk-pjv1ekwr.js} +32 -0
- package/dist/chunk-rz5p4j3p.js +13 -0
- package/dist/modules/elysia/cache/cache.d.ts +7 -13
- 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 +10 -10
- package/dist/modules/elysia/crud/operations/index.js +1 -1
- package/dist/modules/elysia/rate-limit/index.js +51 -26
- 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/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/package.json +26 -21
- 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
|
@@ -35,6 +35,10 @@ var count = (database, tableName, {
|
|
|
35
35
|
content: data
|
|
36
36
|
};
|
|
37
37
|
}, {
|
|
38
|
+
detail: {
|
|
39
|
+
summary: "Count",
|
|
40
|
+
description: `Count ${tableName} records based on query options.`
|
|
41
|
+
},
|
|
38
42
|
...getDbInjection(database),
|
|
39
43
|
body: `${tableName}Count`,
|
|
40
44
|
response: `${tableName}CountResponse200`,
|
|
@@ -63,6 +67,10 @@ var batchDelete = (database, tableName, {
|
|
|
63
67
|
content: data
|
|
64
68
|
};
|
|
65
69
|
}, {
|
|
70
|
+
detail: {
|
|
71
|
+
summary: "Delete",
|
|
72
|
+
description: `Delete ${tableName} records based on query options.`
|
|
73
|
+
},
|
|
66
74
|
...getDbInjection(database),
|
|
67
75
|
body: `${tableName}Delete`,
|
|
68
76
|
response: `${tableName}Response200`,
|
|
@@ -96,6 +104,10 @@ var deleteOne = (database, tableName, {
|
|
|
96
104
|
content: data
|
|
97
105
|
};
|
|
98
106
|
}, {
|
|
107
|
+
detail: {
|
|
108
|
+
summary: "Delete One",
|
|
109
|
+
description: `Delete a single ${tableName} record by its primary key.`
|
|
110
|
+
},
|
|
99
111
|
...getDbInjection(database),
|
|
100
112
|
params: `${tableName}IdParam`,
|
|
101
113
|
response: `${tableName}Response200`,
|
|
@@ -122,6 +134,10 @@ var find = (database, tableName, {
|
|
|
122
134
|
content: data
|
|
123
135
|
};
|
|
124
136
|
}, {
|
|
137
|
+
detail: {
|
|
138
|
+
summary: "Find",
|
|
139
|
+
description: `Find ${tableName} records based on query options.`
|
|
140
|
+
},
|
|
125
141
|
...getDbInjection(database),
|
|
126
142
|
body: `${tableName}Find`,
|
|
127
143
|
response: `${tableName}Response200`,
|
|
@@ -154,6 +170,10 @@ var findOne = (database, tableName, {
|
|
|
154
170
|
content: data
|
|
155
171
|
};
|
|
156
172
|
}, {
|
|
173
|
+
detail: {
|
|
174
|
+
summary: "Find One",
|
|
175
|
+
description: `Find a single ${tableName} record by its primary key.`
|
|
176
|
+
},
|
|
157
177
|
...getDbInjection(database),
|
|
158
178
|
params: `${tableName}IdParam`,
|
|
159
179
|
response: `${tableName}Response200`,
|
|
@@ -181,6 +201,10 @@ var insert = (database, tableName, {
|
|
|
181
201
|
content: data
|
|
182
202
|
};
|
|
183
203
|
}, {
|
|
204
|
+
detail: {
|
|
205
|
+
summary: "Insert",
|
|
206
|
+
description: `Insert one or more records into the ${tableName} table.`
|
|
207
|
+
},
|
|
184
208
|
...getDbInjection(database),
|
|
185
209
|
body: `${tableName}Insert`,
|
|
186
210
|
response: `${tableName}Response200`,
|
|
@@ -208,6 +232,10 @@ var update = (database, tableName, {
|
|
|
208
232
|
content: data
|
|
209
233
|
};
|
|
210
234
|
}, {
|
|
235
|
+
detail: {
|
|
236
|
+
summary: "Update",
|
|
237
|
+
description: `Update one or more ${tableName} records based on query options.`
|
|
238
|
+
},
|
|
211
239
|
...getDbInjection(database),
|
|
212
240
|
body: `${tableName}Update`,
|
|
213
241
|
response: `${tableName}Response200`,
|
|
@@ -242,6 +270,10 @@ var updateOne = (database, tableName, {
|
|
|
242
270
|
content: data
|
|
243
271
|
};
|
|
244
272
|
}, {
|
|
273
|
+
detail: {
|
|
274
|
+
summary: "Update Single Record",
|
|
275
|
+
description: `Update a single record in the ${tableName} table by its primary key.`
|
|
276
|
+
},
|
|
245
277
|
...getDbInjection(database),
|
|
246
278
|
params: `${tableName}IdParam`,
|
|
247
279
|
body: `${tableName}UpdateOne`,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// source/modules/logger/enums/logger-error-keys.ts
|
|
3
|
+
var LOGGER_ERROR_KEYS = {
|
|
4
|
+
BEFORE_EXIT_CLOSE_ERROR: "mrx-core.logger.error.before_exit_close_error",
|
|
5
|
+
BEFORE_EXIT_FLUSH_ERROR: "mrx-core.logger.error.before_exit_flush_error",
|
|
6
|
+
NO_SINKS_PROVIDED: "mrx-core.logger.error.no_sinks_provided",
|
|
7
|
+
REGISTER_SINK_ERROR: "mrx-core.logger.error.register_sink_error",
|
|
8
|
+
SINK_ALREADY_ADDED: "mrx-core.logger.error.sink_already_added",
|
|
9
|
+
SINK_CLOSE_ERROR: "mrx-core.logger.error.sink_close_error",
|
|
10
|
+
SINK_LOG_ERROR: "mrx-core.logger.error.sink_log_error"
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { LOGGER_ERROR_KEYS };
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
|
-
import {
|
|
2
|
+
import type { KvStore } from '../../../modules/kv-store/types';
|
|
3
3
|
import type { CacheOptions } from './types/cache-options';
|
|
4
|
-
export declare const cache: (
|
|
4
|
+
export declare const cache: (store?: KvStore) => Elysia<"", {
|
|
5
5
|
decorator: {};
|
|
6
|
-
store: {
|
|
7
|
-
kvStore: import("../../kv-store/types").KvStore | MemoryStore;
|
|
8
|
-
_cachedRoutes: Set<string>;
|
|
9
|
-
};
|
|
6
|
+
store: {};
|
|
10
7
|
derive: {};
|
|
11
8
|
resolve: {};
|
|
12
9
|
}, {
|
|
@@ -16,11 +13,11 @@ export declare const cache: ({ defaultTtl, prefix, store }?: CacheOptions) => El
|
|
|
16
13
|
schema: {};
|
|
17
14
|
standaloneSchema: {};
|
|
18
15
|
macro: Partial<{
|
|
19
|
-
readonly isCached:
|
|
16
|
+
readonly isCached: CacheOptions;
|
|
20
17
|
}>;
|
|
21
18
|
macroFn: {
|
|
22
|
-
readonly isCached: (
|
|
23
|
-
readonly afterHandle: ({ set, responseValue,
|
|
19
|
+
readonly isCached: ({ ttl, prefix }: CacheOptions) => {
|
|
20
|
+
readonly afterHandle: ({ set, responseValue, request }: {
|
|
24
21
|
body: unknown;
|
|
25
22
|
query: Record<string, string>;
|
|
26
23
|
params: {};
|
|
@@ -37,10 +34,7 @@ export declare const cache: ({ defaultTtl, prefix, store }?: CacheOptions) => El
|
|
|
37
34
|
path: string;
|
|
38
35
|
route: string;
|
|
39
36
|
request: Request;
|
|
40
|
-
store: {
|
|
41
|
-
kvStore: import("../../kv-store/types").KvStore | MemoryStore;
|
|
42
|
-
_cachedRoutes: Set<string>;
|
|
43
|
-
};
|
|
37
|
+
store: {};
|
|
44
38
|
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 420 ? {
|
|
45
39
|
readonly 100: "Continue";
|
|
46
40
|
readonly 101: "Switching Protocols";
|
|
@@ -1,70 +1,90 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
MemoryStore
|
|
4
|
-
} from "
|
|
4
|
+
} from "../../kv-store/memory/index.js";
|
|
5
5
|
import"../../../chunk-xhhj1gvj.js";
|
|
6
|
-
import {
|
|
7
|
-
generateCacheKey
|
|
8
|
-
} from "../../../chunk-b23dvm2d.js";
|
|
9
6
|
import"../../../chunk-9cgzhc50.js";
|
|
10
7
|
|
|
11
8
|
// source/modules/elysia/cache/cache.ts
|
|
12
9
|
import { Elysia } from "elysia";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (cachedData && typeof cachedData === "object" && "response" in cachedData && "metadata" in cachedData) {
|
|
27
|
-
const { response, metadata } = cachedData;
|
|
28
|
-
set.headers["cache-control"] = `max-age=${metadata.ttl}, public`;
|
|
29
|
-
set.headers["x-cache"] = "HIT";
|
|
30
|
-
set.headers["etag"] = `"${prefix}${cacheKey}"`;
|
|
31
|
-
set.headers["expires"] = new Date(Date.now() + metadata.ttl * 1000).toUTCString();
|
|
32
|
-
set.headers["last-modified"] = metadata.createdAt;
|
|
33
|
-
if (response instanceof Response)
|
|
34
|
-
return response.clone();
|
|
35
|
-
return response;
|
|
10
|
+
|
|
11
|
+
// source/modules/elysia/cache/utils/generate-cache-key.ts
|
|
12
|
+
var _calculateBodyHash = async (body, hasher) => {
|
|
13
|
+
if (!body)
|
|
14
|
+
return;
|
|
15
|
+
const reader = body.getReader();
|
|
16
|
+
try {
|
|
17
|
+
while (true) {
|
|
18
|
+
const { done, value } = await reader.read();
|
|
19
|
+
if (done)
|
|
20
|
+
break;
|
|
21
|
+
if (value)
|
|
22
|
+
hasher.update(new Uint8Array(value));
|
|
36
23
|
}
|
|
37
|
-
|
|
24
|
+
} finally {
|
|
25
|
+
reader.releaseLock();
|
|
38
26
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
27
|
+
};
|
|
28
|
+
var generateCacheKey = async (request) => {
|
|
29
|
+
const { method, url, headers } = request;
|
|
30
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
31
|
+
hasher.update(method);
|
|
32
|
+
hasher.update(url);
|
|
33
|
+
hasher.update(JSON.stringify(headers));
|
|
34
|
+
await _calculateBodyHash(request.body, hasher);
|
|
35
|
+
return hasher.digest("hex");
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// source/modules/elysia/cache/cache.ts
|
|
39
|
+
var cache = (store = new MemoryStore) => {
|
|
40
|
+
const cachedRoutes = new Map;
|
|
41
|
+
return new Elysia().onRequest(async ({ request, set }) => {
|
|
42
|
+
const route = `${request.method}:${new URL(request.url).pathname}`;
|
|
43
|
+
if (cachedRoutes.has(route)) {
|
|
44
|
+
const { ttl, prefix } = cachedRoutes.get(route);
|
|
45
|
+
const cacheKey = await generateCacheKey(request.clone());
|
|
46
|
+
const cacheItem = await store.get(`${prefix}${cacheKey}`);
|
|
47
|
+
if (cacheItem && typeof cacheItem === "object" && "response" in cacheItem && "metadata" in cacheItem) {
|
|
48
|
+
const createdAt = new Date(cacheItem.metadata.createdAt);
|
|
49
|
+
const expiresAt = new Date(createdAt.getTime() + ttl * 1000);
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const remaining = Math.max(0, Math.ceil((expiresAt.getTime() - now) / 1000));
|
|
52
|
+
set.headers["cache-control"] = `max-age=${remaining}, public`;
|
|
53
|
+
set.headers["etag"] = `"${prefix}${cacheKey}"`;
|
|
54
|
+
set.headers["last-modified"] = cacheItem.metadata.createdAt;
|
|
55
|
+
set.headers["expires"] = expiresAt.toUTCString();
|
|
56
|
+
set.headers["x-cache"] = "HIT";
|
|
57
|
+
if (cacheItem.response instanceof Response)
|
|
58
|
+
return cacheItem.response.clone();
|
|
59
|
+
return cacheItem.response;
|
|
60
|
+
}
|
|
61
|
+
set.headers["x-cache"] = "MISS";
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}).macro({
|
|
65
|
+
isCached: ({ ttl, prefix = "" }) => ({
|
|
66
|
+
async afterHandle({ set, responseValue, request }) {
|
|
67
|
+
const route = `${request.method}:${new URL(request.url).pathname}`;
|
|
68
|
+
if (!cachedRoutes.has(route))
|
|
69
|
+
cachedRoutes.set(route, { ttl, prefix });
|
|
48
70
|
const cacheKey = await generateCacheKey(request.clone());
|
|
49
71
|
const now = new Date;
|
|
50
72
|
set.headers["cache-control"] = `max-age=${ttl}, public`;
|
|
51
73
|
set.headers["etag"] = `"${prefix}${cacheKey}"`;
|
|
52
74
|
set.headers["last-modified"] = now.toUTCString();
|
|
53
75
|
set.headers["expires"] = new Date(now.getTime() + ttl * 1000).toUTCString();
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const cacheData = {
|
|
76
|
+
set.headers["x-cache"] = "MISS";
|
|
77
|
+
const cacheItem = {
|
|
57
78
|
response: responseValue instanceof Response ? responseValue.clone() : responseValue,
|
|
58
79
|
metadata: {
|
|
59
|
-
createdAt: now.toUTCString()
|
|
60
|
-
ttl
|
|
80
|
+
createdAt: now.toUTCString()
|
|
61
81
|
}
|
|
62
82
|
};
|
|
63
|
-
await
|
|
83
|
+
await store.set(`${prefix}${cacheKey}`, cacheItem, ttl);
|
|
64
84
|
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
85
|
+
})
|
|
86
|
+
});
|
|
87
|
+
};
|
|
68
88
|
export {
|
|
69
89
|
cache
|
|
70
90
|
};
|
|
@@ -1,21 +1,12 @@
|
|
|
1
|
-
import type { KvStore } from '../../../../modules/kv-store/types/kv-store';
|
|
2
1
|
export interface CacheOptions {
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @defaultValue 60
|
|
3
|
+
* TTL in seconds
|
|
7
4
|
*/
|
|
8
|
-
|
|
5
|
+
ttl: number;
|
|
9
6
|
/**
|
|
10
7
|
* Cache key prefix
|
|
11
8
|
*
|
|
12
9
|
* @defaultValue ''
|
|
13
10
|
*/
|
|
14
11
|
prefix?: string;
|
|
15
|
-
/**
|
|
16
|
-
* Storage backend
|
|
17
|
-
*
|
|
18
|
-
* @defaultValue ':memory:'
|
|
19
|
-
*/
|
|
20
|
-
store?: ':memory:' | KvStore;
|
|
21
12
|
}
|
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import {
|
|
3
|
-
batchDelete,
|
|
4
|
-
count,
|
|
5
|
-
deleteOne,
|
|
6
|
-
find,
|
|
7
|
-
findOne,
|
|
8
|
-
insert,
|
|
9
|
-
update,
|
|
10
|
-
updateOne
|
|
11
|
-
} from "../../../chunk-dzfefxjq.js";
|
|
12
2
|
import {
|
|
13
3
|
createCountResponse200Schema,
|
|
14
4
|
createCountSchema,
|
|
@@ -21,6 +11,16 @@ import {
|
|
|
21
11
|
createUpdateSchema
|
|
22
12
|
} from "../../../chunk-p14h6jfs.js";
|
|
23
13
|
import"../../../chunk-9dzsj7f2.js";
|
|
14
|
+
import {
|
|
15
|
+
batchDelete,
|
|
16
|
+
count,
|
|
17
|
+
deleteOne,
|
|
18
|
+
find,
|
|
19
|
+
findOne,
|
|
20
|
+
insert,
|
|
21
|
+
update,
|
|
22
|
+
updateOne
|
|
23
|
+
} from "../../../chunk-pjv1ekwr.js";
|
|
24
24
|
import"../../../chunk-441xs5k1.js";
|
|
25
25
|
import"../../../chunk-fs3wm3p4.js";
|
|
26
26
|
import"../../../chunk-z0ct35ft.js";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "../../../chunk-dre2fgj0.js";
|
|
5
5
|
import {
|
|
6
6
|
MemoryStore
|
|
7
|
-
} from "
|
|
7
|
+
} from "../../kv-store/memory/index.js";
|
|
8
8
|
import"../../../chunk-xhhj1gvj.js";
|
|
9
9
|
import {
|
|
10
10
|
HttpError
|
|
@@ -14,40 +14,65 @@ import"../../../chunk-9cgzhc50.js";
|
|
|
14
14
|
|
|
15
15
|
// source/modules/elysia/rate-limit/rate-limit.ts
|
|
16
16
|
import { Elysia } from "elysia";
|
|
17
|
-
var rateLimit = (
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
window
|
|
25
|
-
|
|
26
|
-
}).onRequest(async ({ set, request, server }) => {
|
|
27
|
-
const ip = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || server?.requestIP(request)?.address || "127.0.0.1";
|
|
28
|
-
const key = `ratelimit:${ip}`;
|
|
29
|
-
const count = await storeInstance.get(key);
|
|
30
|
-
let newCount;
|
|
31
|
-
if (count === null) {
|
|
32
|
-
await storeInstance.set(key, 1, window);
|
|
33
|
-
newCount = 1;
|
|
17
|
+
var rateLimit = (store = new MemoryStore) => {
|
|
18
|
+
const restrictedRoutes = new Map;
|
|
19
|
+
const rateLimitCheck = async (key, limit, window, set) => {
|
|
20
|
+
if (set.headers["X-RateLimit-Limit"])
|
|
21
|
+
return;
|
|
22
|
+
let count = await store.get(key) ?? 0;
|
|
23
|
+
if (count === 0) {
|
|
24
|
+
await store.set(key, 1, window);
|
|
25
|
+
count = 1;
|
|
34
26
|
} else {
|
|
35
|
-
|
|
27
|
+
count = await store.increment(key);
|
|
36
28
|
}
|
|
37
|
-
|
|
29
|
+
const remaining = Math.max(0, limit - count);
|
|
30
|
+
const resetTime = await store.ttl(key);
|
|
31
|
+
set.headers = {
|
|
32
|
+
"X-RateLimit-Limit": limit.toString(),
|
|
33
|
+
"X-RateLimit-Remaining": remaining.toString(),
|
|
34
|
+
"X-RateLimit-Reset": resetTime.toString()
|
|
35
|
+
};
|
|
36
|
+
if (count > limit) {
|
|
38
37
|
set.status = 429;
|
|
39
38
|
throw new HttpError(RATE_LIMIT_ERROR_KEYS.RATE_LIMIT_EXCEEDED, "TOO_MANY_REQUESTS", {
|
|
40
39
|
limit,
|
|
41
40
|
window,
|
|
42
41
|
remaining: 0,
|
|
43
|
-
reset:
|
|
42
|
+
reset: resetTime
|
|
44
43
|
});
|
|
45
44
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
};
|
|
46
|
+
return new Elysia({
|
|
47
|
+
name: "rateLimit",
|
|
48
|
+
seed: {
|
|
49
|
+
store
|
|
50
|
+
}
|
|
51
|
+
}).macro({
|
|
52
|
+
rateLimit: ({ limit, window }) => ({
|
|
53
|
+
transform: ({ request }) => {
|
|
54
|
+
const route = `${request.method}:${new URL(request.url).pathname}`;
|
|
55
|
+
if (!restrictedRoutes.has(route)) {
|
|
56
|
+
restrictedRoutes.set(route, { limit, window });
|
|
57
|
+
} else if (restrictedRoutes.has(route)) {
|
|
58
|
+
const existing = restrictedRoutes.get(route);
|
|
59
|
+
if (limit != existing.limit || window != existing.window)
|
|
60
|
+
restrictedRoutes.set(route, {
|
|
61
|
+
limit,
|
|
62
|
+
window
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
beforeHandle: async ({ set, request, server }) => {
|
|
67
|
+
const route = `${request.method}:${new URL(request.url).pathname}`;
|
|
68
|
+
if (restrictedRoutes.has(route)) {
|
|
69
|
+
const { limit: limit2, window: window2 } = restrictedRoutes.get(route);
|
|
70
|
+
const ip = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || server?.requestIP(request)?.address || "127.0.0.1";
|
|
71
|
+
const key = `ratelimit:${route}:${ip}`;
|
|
72
|
+
await rateLimitCheck(key, limit2, window2, set);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})
|
|
51
76
|
}).as("global");
|
|
52
77
|
};
|
|
53
78
|
export {
|