@limitkit/core 0.1.6 β 0.1.7
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/README.md +104 -64
- package/package.json +43 -29
package/README.md
CHANGED
|
@@ -1,117 +1,157 @@
|
|
|
1
|
-
#
|
|
1
|
+
# π¦ `@limitkit/core`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@limitkit/core)
|
|
4
|
+
[](https://www.npmjs.com/package/@limitkit/core)
|
|
5
|
+
[](https://github.com/alphatrann/limitkit/blob/main/LICENSE)
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
π Main project: https://github.com/alphatrann/limitkit
|
|
7
|
+
**A policy-driven rate limiting engine built on composable rules.**
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# π Works With
|
|
12
|
+
|
|
13
|
+
The core engine is designed to integrate with:
|
|
14
|
+
|
|
15
|
+
* `@limitkit/memory` β in-memory store
|
|
16
|
+
* `@limitkit/redis` β distributed rate limiting
|
|
17
|
+
* `@limitkit/express` β middleware
|
|
18
|
+
* `@limitkit/nest` β guard + decorators
|
|
12
19
|
|
|
13
|
-
```bash
|
|
14
|
-
npm install @limitkit/core
|
|
15
|
-
````
|
|
16
20
|
|
|
17
21
|
---
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
# β‘ Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @limitkit/core
|
|
27
|
+
```
|
|
20
28
|
|
|
21
29
|
```ts
|
|
22
|
-
import { RateLimiter } from "@limitkit/core"
|
|
23
|
-
import { InMemoryStore, InMemoryFixedWindow } from "@limitkit/memory"
|
|
30
|
+
import { RateLimiter } from "@limitkit/core";
|
|
24
31
|
|
|
25
32
|
const limiter = new RateLimiter({
|
|
26
|
-
store
|
|
33
|
+
store,
|
|
27
34
|
rules: [
|
|
28
35
|
{
|
|
29
36
|
name: "global",
|
|
30
|
-
key:
|
|
31
|
-
policy:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
key: "global",
|
|
38
|
+
policy: ...,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const result = await limiter.consume(ctx);
|
|
44
|
+
|
|
45
|
+
if (!result.allowed) {
|
|
46
|
+
console.log("Rate limited");
|
|
47
|
+
}
|
|
39
48
|
```
|
|
40
49
|
|
|
41
50
|
---
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
# π§ Core Idea
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
Most rate limiters answer:
|
|
46
55
|
|
|
47
|
-
|
|
48
|
-
* Sliding Window
|
|
49
|
-
* Sliding Window Counter
|
|
50
|
-
* Token Bucket
|
|
51
|
-
* Leaky Bucket
|
|
52
|
-
* GCRA
|
|
56
|
+
> βHow many requests per IP?β
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
LimitKit answers:
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
> **βWhat rules should control this request?β**
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
```ts
|
|
63
|
+
global β ip β user β endpoint
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Rules run top β bottom and stop on first failure.
|
|
67
|
+
|
|
68
|
+
---
|
|
59
69
|
|
|
60
|
-
|
|
70
|
+
# π§© Concepts
|
|
61
71
|
|
|
62
|
-
|
|
72
|
+
A **rule** defines *who*, *how*, and *how much*:
|
|
63
73
|
|
|
64
74
|
```ts
|
|
65
75
|
{
|
|
66
|
-
name: "
|
|
67
|
-
key: (
|
|
68
|
-
policy: new
|
|
69
|
-
|
|
70
|
-
window: 60,
|
|
71
|
-
limit: 100
|
|
72
|
-
})
|
|
76
|
+
name: "user",
|
|
77
|
+
key: (ctx) => ctx.user.id,
|
|
78
|
+
policy: new TokenBucket(...),
|
|
79
|
+
cost: 1
|
|
73
80
|
}
|
|
74
81
|
```
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
* **key** β groups requests (string, function, or async)
|
|
84
|
+
* **policy** β rate limiting algorithm (fixed, sliding, token bucket)
|
|
85
|
+
* **cost** β weight per request (default: 1)
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
Policies can also be dynamic:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
policy: (ctx) => {
|
|
91
|
+
return ctx.user.plan === "pro" ? proPolicy : freePolicy;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
81
94
|
|
|
82
95
|
---
|
|
83
96
|
|
|
84
|
-
|
|
97
|
+
# π― Examples
|
|
85
98
|
|
|
86
|
-
|
|
99
|
+
## Layered Limits
|
|
87
100
|
|
|
88
101
|
```ts
|
|
89
|
-
|
|
102
|
+
rules: [
|
|
103
|
+
{ name: "global", key: "global", policy: ... },
|
|
104
|
+
{ name: "ip", key: (ctx) => ctx.ip, policy: ... },
|
|
105
|
+
{ name: "user", key: (ctx) => ctx.user.id, policy: ... },
|
|
106
|
+
]
|
|
107
|
+
```
|
|
90
108
|
|
|
91
|
-
|
|
109
|
+
## SaaS Plans
|
|
92
110
|
|
|
93
|
-
|
|
111
|
+
```ts
|
|
112
|
+
{
|
|
113
|
+
key: (ctx) => ctx.user.id,
|
|
114
|
+
policy: (ctx) => {
|
|
115
|
+
return ctx.user.plan === "pro" ? proPolicy : freePolicy;
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
```
|
|
94
119
|
|
|
95
|
-
|
|
96
|
-
if (this.config.limit <= 0) {
|
|
97
|
-
throw new Error("Invalid configuration")
|
|
98
|
-
}
|
|
99
|
-
}
|
|
120
|
+
## Expensive Operations
|
|
100
121
|
|
|
122
|
+
```ts
|
|
123
|
+
{
|
|
124
|
+
key: (ctx) => ctx.user.id,
|
|
125
|
+
cost: (ctx) => ctx.endpoint === "/report" ? 10 : 1,
|
|
126
|
+
policy: tokenBucket,
|
|
101
127
|
}
|
|
102
128
|
```
|
|
103
129
|
|
|
104
130
|
---
|
|
105
131
|
|
|
106
|
-
|
|
132
|
+
# π Result
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
{
|
|
136
|
+
allowed: boolean,
|
|
137
|
+
limit: number,
|
|
138
|
+
remaining: number,
|
|
139
|
+
reset: number,
|
|
140
|
+
retryAfter?: number
|
|
141
|
+
}
|
|
142
|
+
```
|
|
107
143
|
|
|
108
|
-
|
|
144
|
+
* **allowed** β request permitted or blocked
|
|
145
|
+
* **limit** β max allowed requests
|
|
146
|
+
* **remaining** β remaining quota
|
|
147
|
+
* **reset** β timestamp (ms) when fully reset
|
|
148
|
+
* **retryAfter** β seconds to wait (if blocked)
|
|
109
149
|
|
|
110
|
-
|
|
150
|
+
---
|
|
111
151
|
|
|
112
|
-
|
|
152
|
+
# π Summary
|
|
113
153
|
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
154
|
+
* Rule-based rate limiting
|
|
155
|
+
* Dynamic, context-aware policies
|
|
156
|
+
* Weighted requests
|
|
157
|
+
* Early exit for performance
|
package/package.json
CHANGED
|
@@ -1,29 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@limitkit/core",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"main": "dist/index.js",
|
|
5
|
-
"module": "dist/index.mjs",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@limitkit/core",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "dist/index.mjs",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"rate-limiter",
|
|
9
|
+
"rate-limit",
|
|
10
|
+
"rate-limiting",
|
|
11
|
+
"throttling",
|
|
12
|
+
"token-bucket",
|
|
13
|
+
"leaky-bucket",
|
|
14
|
+
"sliding-window",
|
|
15
|
+
"sliding-window-counter",
|
|
16
|
+
"gcra",
|
|
17
|
+
"rules-engine",
|
|
18
|
+
"policy-based",
|
|
19
|
+
"nodejs"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"description": "Core rate limiting engine for LimitKit",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/alphatrann/limitkit"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
38
|
+
"test": "jest --silent"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^25.4.0"
|
|
42
|
+
}
|
|
43
|
+
}
|