@kanjijs/throttler 0.2.0-beta.12 → 0.2.0-beta.13
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/package.json +2 -2
- package/src/throttler.decorator.ts +1 -1
- package/src/throttler.guard.ts +11 -71
- package/src/throttler.module.ts +1 -1
- package/tsconfig.json +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanjijs/throttler",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"reflect-metadata": "^0.2.0"
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"@kanjijs/core": "^0.2.0-beta.
|
|
11
|
+
"@kanjijs/core": "^0.2.0-beta.13"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "bun build ./src/index.ts --outdir ./dist --target bun"
|
|
@@ -10,7 +10,7 @@ export interface ThrottlerOptions {
|
|
|
10
10
|
export function Throttle(options: ThrottlerOptions) {
|
|
11
11
|
return Use(async (c: Context, next: Next) => {
|
|
12
12
|
// Resolve singleton
|
|
13
|
-
const throttler = KanjijsIoC.resolve(ThrottlerService);
|
|
13
|
+
const throttler = KanjijsIoC.resolve(ThrottlerService) as ThrottlerService | undefined;
|
|
14
14
|
|
|
15
15
|
if (throttler) {
|
|
16
16
|
// Use specific options from decorator
|
package/src/throttler.guard.ts
CHANGED
|
@@ -1,85 +1,25 @@
|
|
|
1
1
|
import { Inject, Injectable, GLOBAL_MIDDLEWARE_TOKEN } from "@kanjijs/core";
|
|
2
|
-
import { type Context, type Next } from "hono";
|
|
3
|
-
import {
|
|
4
|
-
import { THROTTLER_LIMIT, THROTTLER_TTL } from "./throttler.decorator";
|
|
5
|
-
|
|
6
|
-
export interface ThrottlerModuleOptions {
|
|
7
|
-
limit?: number;
|
|
8
|
-
ttl?: number;
|
|
9
|
-
storage?: ThrottlerStorage;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const THROTTLER_OPTIONS = "THROTTLER_OPTIONS";
|
|
2
|
+
import { type Context, type Handler, type Next } from "hono";
|
|
3
|
+
import { type ThrottlerModuleOptions, THROTTLER_OPTIONS, ThrottlerService } from "./throttler.service";
|
|
13
4
|
|
|
14
5
|
@Injectable()
|
|
15
6
|
export class ThrottlerGuard {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
constructor(@Inject(THROTTLER_OPTIONS) private options: ThrottlerModuleOptions) {
|
|
21
|
-
this.storage = options.storage || new ThrottlerInMemoryStorage();
|
|
22
|
-
this.defaultLimit = options.limit || 10;
|
|
23
|
-
this.defaultTtl = options.ttl || 60;
|
|
24
|
-
}
|
|
7
|
+
constructor(
|
|
8
|
+
@Inject(ThrottlerService) private throttler: ThrottlerService
|
|
9
|
+
) {}
|
|
25
10
|
|
|
26
11
|
// This will be registered as a Global Middleware in KanjijsAdapter if provided
|
|
27
12
|
async handle(c: Context, next: Next) {
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
/*
|
|
31
|
-
NOTE: In Bun/Hono, getting IP can be platform specific.
|
|
32
|
-
We will trust X-Forwarded-For or use a fallback.
|
|
33
|
-
*/
|
|
34
|
-
const ip = c.req.header("x-forwarded-for") || "unknown";
|
|
35
|
-
const key = `throttler:${ip}:${c.req.path}`; // Limit by IP + Path (or just IP?) -> Usually just IP for global
|
|
36
|
-
|
|
37
|
-
// 2. Resolve Metadata (Limit/TTL)
|
|
38
|
-
// KanjijsAdapter doesn't expose the "Current Handler" to global middleware easily yet in the context.
|
|
39
|
-
// LIMITATION: Global Middleware runs BEFORE routing in Hono standard app.use('*').
|
|
40
|
-
// To support @Throttle decorators, we need to run THIS check inside the route handler wrapper OR
|
|
41
|
-
// we need to access the route handler metadata here.
|
|
42
|
-
|
|
43
|
-
// CURRENT STRATEGY:
|
|
44
|
-
// Global Config applies to ALL routes globally (Middleware style).
|
|
45
|
-
// @Throttle decorator support requires Per-Route logic.
|
|
46
|
-
// Since KanjijsAdapter registers routes, we should probably implement this as a specific middleware wrapper there,
|
|
47
|
-
// OR we rely on Hono context to pass handler info? No standard way.
|
|
48
|
-
|
|
49
|
-
// REVISED PLAN:
|
|
50
|
-
// We will implement `ThrottlerGuard` but we cannot easily use it as a simple `app.use('*')`
|
|
51
|
-
// IF we want to support @Throttle decorators overriding it properly *per route* efficiently without finding the route match twice.
|
|
52
|
-
|
|
53
|
-
// HOWEVER, for MVP:
|
|
54
|
-
// 1. Global Throttling: Runs on `*`, uses default limit.
|
|
55
|
-
// 2. Decorator Throttling: The adapter needs to know about it.
|
|
56
|
-
|
|
57
|
-
// BUT the user asked for: "rate limit haz que tambien se pueda configurar desde main y no solo usando el decorador"
|
|
58
|
-
|
|
59
|
-
// Let's stick to the plan:
|
|
60
|
-
// If we use Global Middleware, we enforce global limit.
|
|
61
|
-
// If we want specific limits, we need `KanjijsAdapter` to help us OR we attach `ThrottlerGuard` to the route in the Adapter.
|
|
62
|
-
|
|
63
|
-
// DECISION:
|
|
64
|
-
// This `handle` method will apply the DEFAULT global limit if installed globally.
|
|
65
|
-
// For Decorator support, `KanjijsAdapter` needs to look for `@Throttle` metadata and add THIS middleware (configured differently) to that route.
|
|
66
|
-
|
|
67
|
-
const limit = this.defaultLimit;
|
|
68
|
-
const ttl = this.defaultTtl;
|
|
13
|
+
// Override global options? For now, simply use global defaults.
|
|
14
|
+
const { limit, ttl } = this.throttler.getGlobalOptions();
|
|
69
15
|
|
|
70
|
-
const
|
|
16
|
+
const allowed = await this.throttler.handleRequest(c, limit, ttl);
|
|
71
17
|
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
18
|
+
if (!allowed) {
|
|
19
|
+
// Response is already handled by service (429)
|
|
20
|
+
return;
|
|
76
21
|
}
|
|
77
22
|
|
|
78
|
-
// Headers
|
|
79
|
-
c.header("X-RateLimit-Limit", limit.toString());
|
|
80
|
-
c.header("X-RateLimit-Remaining", Math.max(0, limit - total).toString());
|
|
81
|
-
c.header("X-RateLimit-Reset", timeToExpire.toString());
|
|
82
|
-
|
|
83
23
|
await next();
|
|
84
24
|
}
|
|
85
25
|
}
|
package/src/throttler.module.ts
CHANGED
|
@@ -17,7 +17,7 @@ export class ThrottlerModule {
|
|
|
17
17
|
provide: GLOBAL_MIDDLEWARE_TOKEN,
|
|
18
18
|
useValue: async (c: Context, next: Next) => {
|
|
19
19
|
// console.log("Throttler Middleware Executing via Global Token");
|
|
20
|
-
const throttler = KanjijsIoC.resolve(ThrottlerService);
|
|
20
|
+
const throttler = KanjijsIoC.resolve(ThrottlerService) as ThrottlerService | undefined;
|
|
21
21
|
if (throttler) {
|
|
22
22
|
const { limit, ttl } = throttler.getGlobalOptions();
|
|
23
23
|
const allowed = await throttler.handleRequest(c, limit, ttl);
|