@kanjijs/throttler 0.2.0-beta.14 → 0.2.0-beta.15
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/index.ts +3 -2
- package/src/throttler.decorator.ts +6 -6
- package/src/throttler.guard.ts +10 -8
- package/src/throttler.module.ts +20 -15
- package/src/throttler.service.ts +2 -2
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.15",
|
|
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.15"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "bun build ./src/index.ts --outdir ./dist --target bun"
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
console.log("Throttler Package Loaded");
|
|
2
|
+
|
|
3
|
+
export * from "./throttler.decorator";
|
|
4
|
+
export * from "./throttler.guard";
|
|
2
5
|
export * from "./throttler.module";
|
|
3
6
|
export * from "./throttler.service";
|
|
4
|
-
export * from "./throttler.decorator";
|
|
5
7
|
export * from "./throttler.storage";
|
|
6
|
-
export * from "./throttler.guard";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { KanjijsIoC, Use } from "@kanjijs/core";
|
|
2
2
|
import { type Context, type Next } from "hono";
|
|
3
3
|
import { ThrottlerService } from "./throttler.service";
|
|
4
4
|
|
|
@@ -11,17 +11,17 @@ export function Throttle(options: ThrottlerOptions) {
|
|
|
11
11
|
return Use(async (c: Context, next: Next) => {
|
|
12
12
|
// Resolve singleton
|
|
13
13
|
const throttler = KanjijsIoC.resolve(ThrottlerService) as ThrottlerService | undefined;
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
if (throttler) {
|
|
16
16
|
// Use specific options from decorator
|
|
17
17
|
const allowed = await throttler.handleRequest(c, options.limit, options.ttl);
|
|
18
18
|
if (!allowed) return; // Blocked (handleRequest sets status/body)
|
|
19
19
|
} else {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// Fallback or warning? If module is not imported, throttler service won't exist.
|
|
21
|
+
// It's safe to just next() or warn.
|
|
22
|
+
console.warn("@Throttle used but ThrottlerModule not imported/provided.");
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
await next();
|
|
26
26
|
});
|
|
27
27
|
}
|
package/src/throttler.guard.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { Inject, Injectable
|
|
2
|
-
import { type Context, type
|
|
3
|
-
import {
|
|
1
|
+
import { Inject, Injectable } from "@kanjijs/core";
|
|
2
|
+
import { type Context, type Next } from "hono";
|
|
3
|
+
import { ThrottlerService } from "./throttler.service";
|
|
4
4
|
|
|
5
5
|
@Injectable()
|
|
6
6
|
export class ThrottlerGuard {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
) {
|
|
7
|
+
private throttler: ThrottlerService;
|
|
8
|
+
|
|
9
|
+
constructor(@Inject(ThrottlerService) throttler: ThrottlerService) {
|
|
10
|
+
this.throttler = throttler;
|
|
11
|
+
}
|
|
10
12
|
|
|
11
13
|
// This will be registered as a Global Middleware in KanjijsAdapter if provided
|
|
12
14
|
async handle(c: Context, next: Next) {
|
|
@@ -16,8 +18,8 @@ export class ThrottlerGuard {
|
|
|
16
18
|
const allowed = await this.throttler.handleRequest(c, limit, ttl);
|
|
17
19
|
|
|
18
20
|
if (!allowed) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
// Response is already handled by service (429)
|
|
22
|
+
return;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
await next();
|
package/src/throttler.module.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GLOBAL_MIDDLEWARE_TOKEN, KanjijsIoC, Module } from "@kanjijs/core";
|
|
2
2
|
import type { Context, Next } from "hono";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
THROTTLER_OPTIONS,
|
|
5
|
+
type ThrottlerModuleOptions,
|
|
6
|
+
ThrottlerService,
|
|
7
|
+
} from "./throttler.service";
|
|
4
8
|
|
|
5
9
|
@Module({})
|
|
10
|
+
// biome-ignore lint/complexity/noStaticOnlyClass: ThrottlerModule is a static module container
|
|
6
11
|
export class ThrottlerModule {
|
|
7
12
|
static forRoot(options: ThrottlerModuleOptions) {
|
|
8
13
|
return {
|
|
@@ -16,19 +21,19 @@ export class ThrottlerModule {
|
|
|
16
21
|
{
|
|
17
22
|
provide: GLOBAL_MIDDLEWARE_TOKEN,
|
|
18
23
|
useValue: async (c: Context, next: Next) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
}
|
|
24
|
+
// console.log("Throttler Middleware Executing via Global Token");
|
|
25
|
+
const throttler = KanjijsIoC.resolve(ThrottlerService) as ThrottlerService | undefined;
|
|
26
|
+
if (throttler) {
|
|
27
|
+
const { limit, ttl } = throttler.getGlobalOptions();
|
|
28
|
+
const allowed = await throttler.handleRequest(c, limit, ttl);
|
|
29
|
+
if (!allowed) {
|
|
30
|
+
c.header("Retry-After", ttl.toString());
|
|
31
|
+
return c.text("Too Many Requests", 429);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
await next();
|
|
35
|
+
},
|
|
36
|
+
},
|
|
32
37
|
],
|
|
33
38
|
exports: [ThrottlerService],
|
|
34
39
|
};
|
package/src/throttler.service.ts
CHANGED
|
@@ -16,7 +16,7 @@ export class ThrottlerService {
|
|
|
16
16
|
private defaultLimit: number;
|
|
17
17
|
private defaultTtl: number;
|
|
18
18
|
|
|
19
|
-
constructor(@Inject(THROTTLER_OPTIONS)
|
|
19
|
+
constructor(@Inject(THROTTLER_OPTIONS) options: ThrottlerModuleOptions) {
|
|
20
20
|
this.storage = options.storage || new ThrottlerInMemoryStorage();
|
|
21
21
|
this.defaultLimit = options.limit || 10;
|
|
22
22
|
this.defaultTtl = options.ttl || 60;
|
|
@@ -29,7 +29,7 @@ export class ThrottlerService {
|
|
|
29
29
|
async handleRequest(c: Context, limit: number, ttl: number): Promise<boolean> {
|
|
30
30
|
const ip = c.req.header("x-forwarded-for") || "unknown";
|
|
31
31
|
const path = c.req.path;
|
|
32
|
-
const key = `throttler:${ip}:${path}`;
|
|
32
|
+
const key = `throttler:${ip}:${path}`;
|
|
33
33
|
|
|
34
34
|
const { total, timeToExpire } = await this.storage.increment(key, ttl);
|
|
35
35
|
|