@roneysilva25/test 1.0.0 → 1.0.2
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/{src/algorithms/Algorithm.interface.ts → dist/algorithms/Algorithm.interface.d.ts} +4 -6
- package/dist/algorithms/Algorithm.interface.d.ts.map +1 -0
- package/dist/algorithms/Algorithm.interface.js +2 -0
- package/dist/algorithms/Algorithm.interface.js.map +1 -0
- package/dist/algorithms/FixedWindow.d.ts +10 -0
- package/dist/algorithms/FixedWindow.d.ts.map +1 -0
- package/dist/algorithms/FixedWindow.interfaces.d.ts +6 -0
- package/dist/algorithms/FixedWindow.interfaces.d.ts.map +1 -0
- package/dist/algorithms/FixedWindow.interfaces.js +2 -0
- package/dist/algorithms/FixedWindow.interfaces.js.map +1 -0
- package/{src/algorithms/FixedWindow.ts → dist/algorithms/FixedWindow.js} +11 -24
- package/dist/algorithms/FixedWindow.js.map +1 -0
- package/dist/controllers/RateLimiterController.d.ts +7 -0
- package/dist/controllers/RateLimiterController.d.ts.map +1 -0
- package/{src/controllers/RateLimiterController.interfaces.ts → dist/controllers/RateLimiterController.interfaces.d.ts} +3 -11
- package/dist/controllers/RateLimiterController.interfaces.d.ts.map +1 -0
- package/dist/controllers/RateLimiterController.interfaces.js +2 -0
- package/dist/controllers/RateLimiterController.interfaces.js.map +1 -0
- package/{src/controllers/RateLimiterController.ts → dist/controllers/RateLimiterController.js} +5 -8
- package/dist/controllers/RateLimiterController.js.map +1 -0
- package/dist/db/Storage.d.ts +10 -0
- package/dist/db/Storage.d.ts.map +1 -0
- package/dist/db/Storage.interfaces.d.ts +6 -0
- package/dist/db/Storage.interfaces.d.ts.map +1 -0
- package/dist/db/Storage.interfaces.js +2 -0
- package/dist/db/Storage.interfaces.js.map +1 -0
- package/dist/db/Storage.js +20 -0
- package/dist/db/Storage.js.map +1 -0
- package/dist/factories/AlgorithmFactory.d.ts +6 -0
- package/dist/factories/AlgorithmFactory.d.ts.map +1 -0
- package/{src/factories/AlgorithmFactory.interfaces.ts → dist/factories/AlgorithmFactory.interfaces.d.ts} +3 -9
- package/dist/factories/AlgorithmFactory.interfaces.d.ts.map +1 -0
- package/dist/factories/AlgorithmFactory.interfaces.js +2 -0
- package/dist/factories/AlgorithmFactory.interfaces.js.map +1 -0
- package/dist/factories/AlgorithmFactory.js +12 -0
- package/dist/factories/AlgorithmFactory.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +8 -21
- package/dist/index.js.map +1 -0
- package/{src/interfaces.ts → dist/interfaces.d.ts} +2 -5
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +2 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/test/FixedWindow.test.d.ts +2 -0
- package/dist/test/FixedWindow.test.d.ts.map +1 -0
- package/{src/test/FixedWindow.test.ts → dist/test/FixedWindow.test.js} +19 -40
- package/dist/test/FixedWindow.test.js.map +1 -0
- package/package.json +2 -2
- package/src/algorithms/FixedWindow.interfaces.ts +0 -8
- package/src/db/Storage.interfaces.ts +0 -8
- package/src/db/Storage.ts +0 -26
- package/src/factories/AlgorithmFactory.ts +0 -14
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import type { Storage } from "../db/Storage.js";
|
|
2
2
|
import type { PacketPayload } from "./FixedWindow.interfaces.js";
|
|
3
|
-
|
|
4
3
|
export interface HandleArgs {
|
|
5
4
|
packetKey: string;
|
|
6
5
|
forwardCb: (packetInfo: PacketPayload) => void;
|
|
7
|
-
dropCb:(packetInfo: PacketPayload) => void;
|
|
6
|
+
dropCb: (packetInfo: PacketPayload) => void;
|
|
8
7
|
}
|
|
9
|
-
|
|
10
8
|
export interface Algorithm {
|
|
11
|
-
readonly storage: typeof Storage
|
|
9
|
+
readonly storage: typeof Storage;
|
|
12
10
|
capacity: number;
|
|
13
11
|
timeWindowInMs: number;
|
|
14
12
|
handle: (args: HandleArgs) => void;
|
|
15
13
|
}
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
export type AlgorithmConstructorArgs = Omit<Algorithm, "handle">;
|
|
15
|
+
//# sourceMappingURL=Algorithm.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Algorithm.interface.d.ts","sourceRoot":"","sources":["../../src/algorithms/Algorithm.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,MAAM,WAAW,UAAU;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,MAAM,EAAC,CAAC,UAAU,EAAE,aAAa,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,OAAO,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Algorithm.interface.js","sourceRoot":"","sources":["../../src/algorithms/Algorithm.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Storage } from "../db/Storage.js";
|
|
2
|
+
import type { HandleArgs, Algorithm, AlgorithmConstructorArgs } from "./Algorithm.interface.js";
|
|
3
|
+
export declare class FixedWindow implements Algorithm {
|
|
4
|
+
capacity: number;
|
|
5
|
+
timeWindowInMs: number;
|
|
6
|
+
storage: typeof Storage;
|
|
7
|
+
constructor({ capacity, timeWindowInMs, storage, }: AlgorithmConstructorArgs);
|
|
8
|
+
handle({ packetKey, forwardCb, dropCb }: HandleArgs): void;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=FixedWindow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindow.d.ts","sourceRoot":"","sources":["../../src/algorithms/FixedWindow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEhG,qBAAa,WAAY,YAAW,SAAS;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,OAAO,CAAC;gBAEZ,EACR,QAAQ,EACR,cAAc,EACd,OAAO,GACV,EAAE,wBAAwB;IAM3B,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,UAAU;CA8BtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindow.interfaces.d.ts","sourceRoot":"","sources":["../../src/algorithms/FixedWindow.interfaces.ts"],"names":[],"mappings":"AAAA,UAAU,aAAa;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,OAAO,EACH,KAAK,aAAa,GACrB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindow.interfaces.js","sourceRoot":"","sources":["../../src/algorithms/FixedWindow.interfaces.ts"],"names":[],"mappings":"AAKA,OAAO,EAEN,CAAA"}
|
|
@@ -1,50 +1,37 @@
|
|
|
1
1
|
import { Storage } from "../db/Storage.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
capacity
|
|
7
|
-
timeWindowInMs: number;
|
|
8
|
-
storage: typeof Storage;
|
|
9
|
-
|
|
10
|
-
constructor({
|
|
11
|
-
capacity,
|
|
12
|
-
timeWindowInMs,
|
|
13
|
-
storage,
|
|
14
|
-
}: AlgorithmConstructorArgs) {
|
|
2
|
+
export class FixedWindow {
|
|
3
|
+
capacity;
|
|
4
|
+
timeWindowInMs;
|
|
5
|
+
storage;
|
|
6
|
+
constructor({ capacity, timeWindowInMs, storage, }) {
|
|
15
7
|
this.capacity = capacity;
|
|
16
8
|
this.timeWindowInMs = timeWindowInMs;
|
|
17
9
|
this.storage = storage;
|
|
18
10
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const existingPacket = this.storage.retrieve<PacketPayload>(packetKey);
|
|
11
|
+
handle({ packetKey, forwardCb, dropCb }) {
|
|
12
|
+
const existingPacket = this.storage.retrieve(packetKey);
|
|
22
13
|
const currentTime = new Date().getTime();
|
|
23
|
-
|
|
24
14
|
if (!existingPacket || currentTime - existingPacket.createdAt >= this.timeWindowInMs) {
|
|
25
|
-
const createdPacket = this.storage.store
|
|
15
|
+
const createdPacket = this.storage.store({
|
|
26
16
|
key: packetKey,
|
|
27
17
|
payload: {
|
|
28
18
|
createdAt: currentTime,
|
|
29
19
|
allowance: this.capacity - 1,
|
|
30
20
|
},
|
|
31
21
|
});
|
|
32
|
-
|
|
33
22
|
return forwardCb(createdPacket);
|
|
34
23
|
}
|
|
35
|
-
|
|
36
24
|
if (existingPacket.allowance - 1 >= 0) {
|
|
37
|
-
const updatedPacket = this.storage.store
|
|
25
|
+
const updatedPacket = this.storage.store({
|
|
38
26
|
key: packetKey,
|
|
39
27
|
payload: {
|
|
40
28
|
createdAt: existingPacket.createdAt,
|
|
41
29
|
allowance: existingPacket.allowance - 1,
|
|
42
30
|
},
|
|
43
31
|
});
|
|
44
|
-
|
|
45
32
|
return forwardCb(updatedPacket);
|
|
46
33
|
}
|
|
47
|
-
|
|
48
34
|
return dropCb(existingPacket);
|
|
49
35
|
}
|
|
50
|
-
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=FixedWindow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindow.js","sourceRoot":"","sources":["../../src/algorithms/FixedWindow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,MAAM,OAAO,WAAW;IACpB,QAAQ,CAAS;IACjB,cAAc,CAAS;IACvB,OAAO,CAAiB;IAExB,YAAY,EACR,QAAQ,EACR,cAAc,EACd,OAAO,GACgB;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAc;QAC/C,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAgB,SAAS,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QAEzC,IAAI,CAAC,cAAc,IAAI,WAAW,GAAG,cAAc,CAAC,SAAS,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACnF,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAgB;gBACpD,GAAG,EAAE,SAAS;gBACd,OAAO,EAAE;oBACL,SAAS,EAAE,WAAW;oBACtB,SAAS,EAAE,IAAI,CAAC,QAAQ,GAAG,CAAC;iBAC/B;aACJ,CAAC,CAAC;YAEH,OAAO,SAAS,CAAC,aAAa,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,cAAc,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAgB;gBACpD,GAAG,EAAE,SAAS;gBACd,OAAO,EAAE;oBACL,SAAS,EAAE,cAAc,CAAC,SAAS;oBACnC,SAAS,EAAE,cAAc,CAAC,SAAS,GAAG,CAAC;iBAC1C;aACJ,CAAC,CAAC;YAEH,OAAO,SAAS,CAAC,aAAa,CAAC,CAAC;QACpC,CAAC;QAED,OAAO,MAAM,CAAC,cAAc,CAAC,CAAC;IAClC,CAAC;CACJ"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DropArgs, ForwardArgs } from "./RateLimiterController.interfaces.js";
|
|
2
|
+
export declare class RateLimiterController {
|
|
3
|
+
private configResponseHeaders;
|
|
4
|
+
drop({ res, req, packetInfo, limiterInfo }: DropArgs): import("express").Response<any, Record<string, any>>;
|
|
5
|
+
forward({ req, res, next, packetInfo, limiterInfo }: ForwardArgs): void;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=RateLimiterController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterController.d.ts","sourceRoot":"","sources":["../../src/controllers/RateLimiterController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,QAAQ,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAE1G,qBAAa,qBAAqB;IAC9B,OAAO,CAAC,qBAAqB;IAOtB,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,QAAQ;IAKpD,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,WAAW;CAI1E"}
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
import type { PacketPayload } from "../algorithms/FixedWindow.interfaces.js";
|
|
2
|
-
import type { NextFunction, Response, Request
|
|
3
|
-
|
|
2
|
+
import type { NextFunction, Response, Request } from "express";
|
|
4
3
|
interface LimiterInfo {
|
|
5
4
|
capacity: number;
|
|
6
5
|
timeWindowInMs: number;
|
|
7
6
|
}
|
|
8
|
-
|
|
9
7
|
interface ConfigResponseHeaders {
|
|
10
8
|
res: Response;
|
|
11
9
|
packetInfo: PacketPayload;
|
|
12
10
|
limiterInfo: LimiterInfo;
|
|
13
11
|
}
|
|
14
|
-
|
|
15
12
|
interface DropArgs {
|
|
16
13
|
req: Request;
|
|
17
14
|
res: Response;
|
|
18
15
|
packetInfo: PacketPayload;
|
|
19
16
|
limiterInfo: LimiterInfo;
|
|
20
17
|
}
|
|
21
|
-
|
|
22
18
|
interface ForwardArgs {
|
|
23
19
|
req: Request;
|
|
24
20
|
res: Response;
|
|
@@ -26,9 +22,5 @@ interface ForwardArgs {
|
|
|
26
22
|
packetInfo: PacketPayload;
|
|
27
23
|
limiterInfo: LimiterInfo;
|
|
28
24
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
ConfigResponseHeaders,
|
|
32
|
-
DropArgs,
|
|
33
|
-
ForwardArgs,
|
|
34
|
-
}
|
|
25
|
+
export type { ConfigResponseHeaders, DropArgs, ForwardArgs, };
|
|
26
|
+
//# sourceMappingURL=RateLimiterController.interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterController.interfaces.d.ts","sourceRoot":"","sources":["../../src/controllers/RateLimiterController.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAG,MAAM,SAAS,CAAC;AAEhE,UAAU,WAAW;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,qBAAqB;IAC3B,GAAG,EAAE,QAAQ,CAAC;IACd,UAAU,EAAE,aAAa,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED,UAAU,QAAQ;IACd,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;IACd,UAAU,EAAE,aAAa,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED,UAAU,WAAW;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,aAAa,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED,YAAY,EACR,qBAAqB,EACrB,QAAQ,EACR,WAAW,GACd,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterController.interfaces.js","sourceRoot":"","sources":["../../src/controllers/RateLimiterController.interfaces.ts"],"names":[],"mappings":""}
|
package/{src/controllers/RateLimiterController.ts → dist/controllers/RateLimiterController.js}
RENAMED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import type { ConfigResponseHeaders, DropArgs, ForwardArgs } from "./RateLimiterController.interfaces.js";
|
|
2
|
-
|
|
3
1
|
export class RateLimiterController {
|
|
4
|
-
|
|
2
|
+
configResponseHeaders({ limiterInfo, packetInfo, res }) {
|
|
5
3
|
const resetsIn = limiterInfo.timeWindowInMs + packetInfo.createdAt - new Date().getTime();
|
|
6
4
|
res.setHeader("X-RateLimit-Limit", limiterInfo.capacity);
|
|
7
5
|
res.setHeader("X-RateLimit-Remaining", packetInfo.allowance);
|
|
8
6
|
res.setHeader("X-RateLimit-Reset", resetsIn);
|
|
9
7
|
}
|
|
10
|
-
|
|
11
|
-
public drop({ res, req, packetInfo, limiterInfo }: DropArgs) {
|
|
8
|
+
drop({ res, req, packetInfo, limiterInfo }) {
|
|
12
9
|
this.configResponseHeaders({ res, limiterInfo, packetInfo });
|
|
13
10
|
return res.status(429).send();
|
|
14
11
|
}
|
|
15
|
-
|
|
16
|
-
public forward({ req, res, next, packetInfo, limiterInfo }: ForwardArgs) {
|
|
12
|
+
forward({ req, res, next, packetInfo, limiterInfo }) {
|
|
17
13
|
this.configResponseHeaders({ res, limiterInfo, packetInfo });
|
|
18
14
|
next();
|
|
19
15
|
}
|
|
20
|
-
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=RateLimiterController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiterController.js","sourceRoot":"","sources":["../../src/controllers/RateLimiterController.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAqB;IACtB,qBAAqB,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,EAA0B;QAClF,MAAM,QAAQ,GAAG,WAAW,CAAC,cAAc,GAAG,UAAU,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QAC1F,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;QACzD,GAAG,CAAC,SAAS,CAAC,uBAAuB,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;QAC7D,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAEM,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAY;QACvD,IAAI,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;QAC7D,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC;IAEM,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAe;QACnE,IAAI,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;QAC7D,IAAI,EAAE,CAAC;IACX,CAAC;CACJ"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StoreArgs } from "./Storage.interfaces.js";
|
|
2
|
+
export declare class Storage {
|
|
3
|
+
private static instance;
|
|
4
|
+
private storage;
|
|
5
|
+
private constructor();
|
|
6
|
+
private static getInstance;
|
|
7
|
+
static store<Payload>({ key, payload }: StoreArgs<Payload>): Payload;
|
|
8
|
+
static retrieve<Payload>(key: string): Payload | undefined;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../src/db/Storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,qBAAa,OAAO;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAU;IACjC,OAAO,CAAC,OAAO,CAAmB;IAElC,OAAO;IAIP,OAAO,CAAC,MAAM,CAAC,WAAW;WAQZ,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO;WAI7D,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;CAGpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Storage.interfaces.d.ts","sourceRoot":"","sources":["../../src/db/Storage.interfaces.ts"],"names":[],"mappings":"AAAA,UAAU,SAAS,CAAC,OAAO;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,OAAO,EACH,KAAK,SAAS,GACjB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Storage.interfaces.js","sourceRoot":"","sources":["../../src/db/Storage.interfaces.ts"],"names":[],"mappings":"AAKA,OAAO,EAEN,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class Storage {
|
|
2
|
+
static instance;
|
|
3
|
+
storage;
|
|
4
|
+
constructor() {
|
|
5
|
+
this.storage = new Map();
|
|
6
|
+
}
|
|
7
|
+
static getInstance() {
|
|
8
|
+
if (!this.instance) {
|
|
9
|
+
this.instance = new Storage();
|
|
10
|
+
}
|
|
11
|
+
return this.instance;
|
|
12
|
+
}
|
|
13
|
+
static store({ key, payload }) {
|
|
14
|
+
return this.getInstance().storage.set(key, payload).get(key);
|
|
15
|
+
}
|
|
16
|
+
static retrieve(key) {
|
|
17
|
+
return this.getInstance().storage.get(key);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=Storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Storage.js","sourceRoot":"","sources":["../../src/db/Storage.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,OAAO;IACR,MAAM,CAAC,QAAQ,CAAU;IACzB,OAAO,CAAmB;IAElC;QACI,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;IAC7B,CAAC;IAEO,MAAM,CAAC,WAAW;QACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,OAAO,EAAE,CAAC;QAClC,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAEM,MAAM,CAAC,KAAK,CAAU,EAAE,GAAG,EAAE,OAAO,EAAsB;QAC7D,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjE,CAAC;IAEM,MAAM,CAAC,QAAQ,CAAU,GAAW;QACvC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;CACJ"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Algorithm } from "../algorithms/Algorithm.interface.js";
|
|
2
|
+
import type { GetArgs, IAlgorithmFactory } from "./AlgorithmFactory.interfaces.js";
|
|
3
|
+
export declare class AlgorithmFactory implements IAlgorithmFactory {
|
|
4
|
+
get({ algorithm, config }: GetArgs): Algorithm;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=AlgorithmFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlgorithmFactory.d.ts","sourceRoot":"","sources":["../../src/factories/AlgorithmFactory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAEnF,qBAAa,gBAAiB,YAAW,iBAAiB;IAC/C,GAAG,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,GAAG,SAAS;CAQxD"}
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import type { Algorithm, AlgorithmConstructorArgs } from "../algorithms/Algorithm.interface.js";
|
|
2
|
-
|
|
3
2
|
type Algorithms = "fixed_window";
|
|
4
|
-
|
|
5
3
|
interface GetArgs {
|
|
6
4
|
algorithm: Algorithms;
|
|
7
5
|
config: AlgorithmConstructorArgs;
|
|
8
6
|
}
|
|
9
|
-
|
|
10
7
|
interface IAlgorithmFactory {
|
|
11
|
-
get(args: GetArgs): Algorithm;
|
|
8
|
+
get(args: GetArgs): Algorithm;
|
|
12
9
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type IAlgorithmFactory,
|
|
16
|
-
type GetArgs,
|
|
17
|
-
}
|
|
10
|
+
export { type IAlgorithmFactory, type GetArgs, };
|
|
11
|
+
//# sourceMappingURL=AlgorithmFactory.interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlgorithmFactory.interfaces.d.ts","sourceRoot":"","sources":["../../src/factories/AlgorithmFactory.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhG,KAAK,UAAU,GAAG,cAAc,CAAC;AAEjC,UAAU,OAAO;IACb,SAAS,EAAE,UAAU,CAAC;IACtB,MAAM,EAAE,wBAAwB,CAAC;CACpC;AAED,UAAU,iBAAiB;IACvB,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,OAAO,GACf,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlgorithmFactory.interfaces.js","sourceRoot":"","sources":["../../src/factories/AlgorithmFactory.interfaces.ts"],"names":[],"mappings":"AAaA,OAAO,EAGN,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FixedWindow } from "../algorithms/FixedWindow.js";
|
|
2
|
+
export class AlgorithmFactory {
|
|
3
|
+
get({ algorithm, config }) {
|
|
4
|
+
switch (algorithm) {
|
|
5
|
+
case "fixed_window":
|
|
6
|
+
return new FixedWindow(config);
|
|
7
|
+
default:
|
|
8
|
+
throw new Error(`Unknown algorithm: ${algorithm}.`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=AlgorithmFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlgorithmFactory.js","sourceRoot":"","sources":["../../src/factories/AlgorithmFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAI3D,MAAM,OAAO,gBAAgB;IAClB,GAAG,CAAC,EAAE,SAAS,EAAE,MAAM,EAAW;QACrC,QAAQ,SAAS,EAAE,CAAC;YAChB,KAAK,cAAc;gBACf,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;YACnC;gBACI,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,GAAG,CAAC,CAAC;QAC5D,CAAC;IACL,CAAC;CACJ"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from "express";
|
|
2
|
+
import type { RateLimiterArgs } from "./interfaces.js";
|
|
3
|
+
declare function rateLimiter({ algorithm, capacity, timeWindowInMs, storage }: RateLimiterArgs): {
|
|
4
|
+
limit(req: Request, res: Response, next: NextFunction): void;
|
|
5
|
+
};
|
|
6
|
+
export { rateLimiter, };
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAI/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAQvD,iBAAS,WAAW,CAAC,EACjB,SAAS,EACT,QAAQ,EACR,cAAc,EACd,OAAiB,EACpB,EAAE,eAAe;eAYC,OAAO,OAAO,QAAQ,QAAQ,YAAY;EA2B5D;AAED,OAAO,EACH,WAAW,GACd,CAAA"}
|
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
import type { NextFunction, Request, Response } from "express";
|
|
2
1
|
import { Storage } from "./db/Storage.js";
|
|
3
2
|
import { RateLimiterController } from "./controllers/RateLimiterController.js";
|
|
4
3
|
import { AlgorithmFactory } from "./factories/AlgorithmFactory.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
function validateIP(req: Request, res: Response) {
|
|
4
|
+
function validateIP(req, res) {
|
|
8
5
|
if (!req.ip) {
|
|
9
6
|
return res.status(400).send("Invalid IP Address.");
|
|
10
7
|
}
|
|
11
8
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
algorithm,
|
|
15
|
-
capacity,
|
|
16
|
-
timeWindowInMs,
|
|
17
|
-
storage = Storage
|
|
18
|
-
}: RateLimiterArgs) {
|
|
19
|
-
const controller = new RateLimiterController();
|
|
9
|
+
function rateLimiter({ algorithm, capacity, timeWindowInMs, storage = Storage }) {
|
|
10
|
+
const controller = new RateLimiterController();
|
|
20
11
|
const algFactory = new AlgorithmFactory().get({
|
|
21
12
|
algorithm,
|
|
22
13
|
config: {
|
|
@@ -25,13 +16,11 @@ function rateLimiter({
|
|
|
25
16
|
capacity,
|
|
26
17
|
},
|
|
27
18
|
});
|
|
28
|
-
|
|
29
19
|
return {
|
|
30
|
-
limit(req
|
|
20
|
+
limit(req, res, next) {
|
|
31
21
|
validateIP(req, res);
|
|
32
|
-
|
|
33
22
|
return algFactory.handle({
|
|
34
|
-
packetKey: req.ip
|
|
23
|
+
packetKey: req.ip,
|
|
35
24
|
dropCb: (packetInfo) => controller.drop({
|
|
36
25
|
req,
|
|
37
26
|
res,
|
|
@@ -53,9 +42,7 @@ function rateLimiter({
|
|
|
53
42
|
}),
|
|
54
43
|
});
|
|
55
44
|
}
|
|
56
|
-
}
|
|
45
|
+
};
|
|
57
46
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
rateLimiter,
|
|
61
|
-
}
|
|
47
|
+
export { rateLimiter, };
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGnE,SAAS,UAAU,CAAC,GAAY,EAAE,GAAa;IAC3C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACvD,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,EACjB,SAAS,EACT,QAAQ,EACR,cAAc,EACd,OAAO,GAAG,OAAO,EACH;IACd,MAAM,UAAU,GAAG,IAAI,qBAAqB,EAAE,CAAC;IAC/C,MAAM,UAAU,GAAG,IAAI,gBAAgB,EAAE,CAAC,GAAG,CAAC;QAC1C,SAAS;QACT,MAAM,EAAE;YACJ,cAAc;YACd,OAAO;YACP,QAAQ;SACX;KACJ,CAAC,CAAC;IAEH,OAAO;QACH,KAAK,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;YACjD,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAErB,OAAO,UAAU,CAAC,MAAM,CAAC;gBACrB,SAAS,EAAE,GAAG,CAAC,EAAY;gBAC3B,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;oBACpC,GAAG;oBACH,GAAG;oBACH,UAAU;oBACV,WAAW,EAAE;wBACT,QAAQ;wBACR,cAAc;qBACjB;iBACJ,CAAC;gBACF,SAAS,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;oBAC1C,GAAG;oBACH,GAAG;oBACH,IAAI;oBACJ,UAAU;oBACV,WAAW,EAAE;wBACT,QAAQ;wBACR,cAAc;qBACjB;iBACJ,CAAC;aACL,CAAC,CAAC;QACP,CAAC;KACJ,CAAA;AACL,CAAC;AAED,OAAO,EACH,WAAW,GACd,CAAA"}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import type { Storage } from "./db/Storage.js";
|
|
2
|
-
|
|
3
2
|
interface RateLimiterArgs {
|
|
4
3
|
algorithm: "fixed_window";
|
|
5
4
|
capacity: number;
|
|
6
5
|
timeWindowInMs: number;
|
|
7
6
|
storage?: typeof Storage;
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
RateLimiterArgs
|
|
12
|
-
}
|
|
8
|
+
export type { RateLimiterArgs };
|
|
9
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,UAAU,eAAe;IACrB,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC;CAC5B;AAED,YAAY,EACR,eAAe,EAClB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindow.test.d.ts","sourceRoot":"","sources":["../../src/test/FixedWindow.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,121 +1,100 @@
|
|
|
1
1
|
import { FixedWindow } from "../algorithms/FixedWindow.js";
|
|
2
|
-
|
|
3
2
|
describe("FixedWindow", () => {
|
|
4
3
|
afterEach(() => {
|
|
5
4
|
jest.clearAllMocks();
|
|
6
5
|
});
|
|
7
|
-
|
|
8
6
|
const mockGetTime = jest.fn();
|
|
9
7
|
const mockStore = jest.fn();
|
|
10
8
|
const mockRetrieve = jest.fn();
|
|
11
9
|
const mockStorage = {
|
|
12
10
|
store: mockStore,
|
|
13
|
-
retrieve: mockRetrieve,
|
|
14
|
-
}
|
|
11
|
+
retrieve: mockRetrieve,
|
|
12
|
+
};
|
|
15
13
|
const mockDropCb = jest.fn();
|
|
16
14
|
const mockForwardCb = jest.fn();
|
|
17
|
-
|
|
18
15
|
const fixedWindowArgs = {
|
|
19
16
|
capacity: 200,
|
|
20
|
-
timeWindowInMs: 1000*60*2,
|
|
17
|
+
timeWindowInMs: 1000 * 60 * 2,
|
|
21
18
|
storage: mockStorage,
|
|
22
|
-
}
|
|
23
|
-
|
|
19
|
+
};
|
|
24
20
|
//@ts-ignore
|
|
25
21
|
const fixedWindow = new FixedWindow(fixedWindowArgs);
|
|
26
|
-
|
|
27
22
|
jest.spyOn(Date.prototype, "getTime").mockImplementation(mockGetTime);
|
|
28
|
-
|
|
29
23
|
it("should create a packet with maximum allowance, the current timestamp and call forwardCb, all if the packet does not exist yet ", () => {
|
|
30
24
|
const createdPacket = {
|
|
31
25
|
key: "packetKey",
|
|
32
26
|
payload: {
|
|
33
27
|
createdAt: 1,
|
|
34
|
-
allowance: fixedWindowArgs.capacity - 1,
|
|
28
|
+
allowance: fixedWindowArgs.capacity - 1,
|
|
35
29
|
},
|
|
36
|
-
}
|
|
37
|
-
|
|
30
|
+
};
|
|
38
31
|
mockGetTime.mockReturnValueOnce(1);
|
|
39
32
|
mockRetrieve.mockReturnValueOnce(undefined);
|
|
40
33
|
mockStore.mockReturnValueOnce(createdPacket);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
packetKey: "packetKey",
|
|
34
|
+
fixedWindow.handle({
|
|
35
|
+
packetKey: "packetKey",
|
|
44
36
|
dropCb: mockDropCb,
|
|
45
37
|
forwardCb: mockForwardCb,
|
|
46
38
|
});
|
|
47
|
-
|
|
48
39
|
expect(mockStore).toHaveBeenCalledWith(createdPacket);
|
|
49
40
|
expect(mockForwardCb).toHaveBeenCalledWith(createdPacket);
|
|
50
41
|
});
|
|
51
|
-
|
|
52
42
|
it("should update an existing packet with reset allowance and timestamp, and call forwardCb if the time window has passed", () => {
|
|
53
|
-
const resetAllowance = fixedWindowArgs.capacity - 1
|
|
43
|
+
const resetAllowance = fixedWindowArgs.capacity - 1;
|
|
54
44
|
const updatedPacket = {
|
|
55
45
|
createdAt: fixedWindowArgs.timeWindowInMs,
|
|
56
46
|
allowance: resetAllowance,
|
|
57
47
|
};
|
|
58
48
|
const currentTimestamp = fixedWindowArgs.timeWindowInMs;
|
|
59
|
-
|
|
60
49
|
mockGetTime.mockReturnValueOnce(currentTimestamp);
|
|
61
50
|
mockRetrieve.mockReturnValueOnce({
|
|
62
51
|
createdAt: 0,
|
|
63
52
|
allowance: 10,
|
|
64
53
|
});
|
|
65
54
|
mockStore.mockReturnValueOnce(updatedPacket);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
packetKey: "packetKey",
|
|
55
|
+
fixedWindow.handle({
|
|
56
|
+
packetKey: "packetKey",
|
|
69
57
|
dropCb: mockDropCb,
|
|
70
58
|
forwardCb: mockForwardCb,
|
|
71
59
|
});
|
|
72
|
-
|
|
73
60
|
expect(mockForwardCb).toHaveBeenCalledWith(updatedPacket);
|
|
74
61
|
});
|
|
75
|
-
|
|
76
62
|
it("should update an existing packet, decreasing its allowance by 1 and keeping the same createdAt timestamp, when the allowance has not reached 0 (zero)", () => {
|
|
77
63
|
const foundPacket = {
|
|
78
64
|
createdAt: 10,
|
|
79
65
|
allowance: 4,
|
|
80
|
-
}
|
|
81
|
-
|
|
66
|
+
};
|
|
82
67
|
const updatedPacket = {
|
|
83
68
|
createdAt: foundPacket.createdAt,
|
|
84
69
|
allowance: 3,
|
|
85
|
-
}
|
|
86
|
-
|
|
70
|
+
};
|
|
87
71
|
mockGetTime.mockReturnValueOnce(foundPacket.createdAt + 1);
|
|
88
72
|
mockRetrieve.mockReturnValueOnce(foundPacket);
|
|
89
73
|
mockStore.mockReturnValueOnce(updatedPacket);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
packetKey: "packetKey",
|
|
74
|
+
fixedWindow.handle({
|
|
75
|
+
packetKey: "packetKey",
|
|
93
76
|
dropCb: mockDropCb,
|
|
94
77
|
forwardCb: mockForwardCb,
|
|
95
78
|
});
|
|
96
|
-
|
|
97
79
|
expect(mockStore).toHaveBeenCalledWith({
|
|
98
80
|
key: "packetKey",
|
|
99
81
|
payload: updatedPacket,
|
|
100
82
|
});
|
|
101
83
|
expect(mockForwardCb).toHaveBeenCalledWith(updatedPacket);
|
|
102
84
|
});
|
|
103
|
-
|
|
104
85
|
it("should call the dropCb when the allowance has already reached zero.", () => {
|
|
105
86
|
const foundPacket = {
|
|
106
87
|
createdAt: 10,
|
|
107
88
|
allowance: 0,
|
|
108
89
|
};
|
|
109
|
-
|
|
110
90
|
mockGetTime.mockReturnValueOnce(foundPacket.createdAt + 10);
|
|
111
91
|
mockRetrieve.mockReturnValueOnce(foundPacket);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
packetKey: "packetKey",
|
|
92
|
+
fixedWindow.handle({
|
|
93
|
+
packetKey: "packetKey",
|
|
115
94
|
dropCb: mockDropCb,
|
|
116
95
|
forwardCb: mockForwardCb,
|
|
117
96
|
});
|
|
118
|
-
|
|
119
97
|
expect(mockDropCb).toHaveBeenCalledWith(foundPacket);
|
|
120
98
|
});
|
|
121
|
-
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=FixedWindow.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FixedWindow.test.js","sourceRoot":"","sources":["../../src/test/FixedWindow.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roneysilva25/test",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Implementation of the most common rate limiting algorithms: Fixed Window, Sliding Window, Leaky Bucket, Token Bucket. To be used as middleware for express applications.",
|
|
5
5
|
"homepage": "https://github.com/roneysilva25/rate-limiter#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"author": "Roney Silva <roney.diego000@gmail.com> (https://roneysilva25.github.io/portfolio)",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"main": "./index.js",
|
|
17
|
-
"files": ["dist"
|
|
17
|
+
"files": ["dist"],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"test": "npx jest --watch",
|
|
20
20
|
"clean": "rm -rf ./dist",
|
package/src/db/Storage.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { StoreArgs } from "./Storage.interfaces.js";
|
|
2
|
-
|
|
3
|
-
export class Storage {
|
|
4
|
-
private static instance: Storage;
|
|
5
|
-
private storage: Map<string, any>;
|
|
6
|
-
|
|
7
|
-
private constructor() {
|
|
8
|
-
this.storage = new Map();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
private static getInstance(): Storage {
|
|
12
|
-
if (!this.instance) {
|
|
13
|
-
this.instance = new Storage();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return this.instance;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public static store<Payload>({ key, payload }: StoreArgs<Payload>): Payload {
|
|
20
|
-
return this.getInstance().storage.set(key, payload).get(key);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public static retrieve<Payload>(key: string): Payload | undefined {
|
|
24
|
-
return this.getInstance().storage.get(key);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { FixedWindow } from "../algorithms/FixedWindow.js";
|
|
2
|
-
import type { Algorithm } from "../algorithms/Algorithm.interface.js";
|
|
3
|
-
import type { GetArgs, IAlgorithmFactory } from "./AlgorithmFactory.interfaces.js";
|
|
4
|
-
|
|
5
|
-
export class AlgorithmFactory implements IAlgorithmFactory {
|
|
6
|
-
public get({ algorithm, config }: GetArgs): Algorithm {
|
|
7
|
-
switch (algorithm) {
|
|
8
|
-
case "fixed_window":
|
|
9
|
-
return new FixedWindow(config);
|
|
10
|
-
default:
|
|
11
|
-
throw new Error(`Unknown algorithm: ${algorithm}.`);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|