@joint-ops/hitlimit 1.0.1 → 1.0.3
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 +6 -6
- package/dist/core/limiter.d.ts +8 -0
- package/dist/core/limiter.d.ts.map +1 -1
- package/dist/core/limiter.js +34 -5
- package/dist/core/limiter.js.map +1 -1
- package/dist/core/utils.d.ts +0 -1
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/core/utils.js +0 -4
- package/dist/core/utils.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +117 -8
- package/dist/index.js.map +1 -1
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/memory.js +25 -21
- package/dist/stores/memory.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
- **Blazing Fast** - 400,000+ ops/sec with memory store, ~7% HTTP overhead
|
|
18
18
|
- **Zero Config** - Works out of the box with sensible defaults
|
|
19
|
-
- **Tiny Footprint** - Only ~
|
|
19
|
+
- **Tiny Footprint** - Only ~7KB core, zero runtime dependencies
|
|
20
20
|
- **Framework Agnostic** - Express, NestJS, Fastify, native HTTP
|
|
21
21
|
- **Multiple Stores** - Memory, Redis, SQLite for distributed systems
|
|
22
22
|
- **TypeScript First** - Full type safety and IntelliSense support
|
|
@@ -38,11 +38,11 @@ hitlimit is designed for speed. Here's how it performs:
|
|
|
38
38
|
|
|
39
39
|
### vs Competitors
|
|
40
40
|
|
|
41
|
-
| Library | Memory (ops/s) | Bundle Size |
|
|
42
|
-
|
|
43
|
-
| **hitlimit** | **
|
|
44
|
-
| rate-limiter-flexible |
|
|
45
|
-
| express-rate-limit |
|
|
41
|
+
| Library | Memory 10K IPs (ops/s) | Bundle Size |
|
|
42
|
+
|---------|------------------------|-------------|
|
|
43
|
+
| **hitlimit** | **2,320,000** | **~7KB** |
|
|
44
|
+
| rate-limiter-flexible | 1,630,000 | ~155KB |
|
|
45
|
+
| express-rate-limit | 1,220,000 | ~66KB |
|
|
46
46
|
|
|
47
47
|
### HTTP Overhead
|
|
48
48
|
|
package/dist/core/limiter.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import type { HitLimitResult, ResolvedConfig } from '@joint-ops/hitlimit-types';
|
|
2
|
+
export interface FastResult {
|
|
3
|
+
allowed: boolean;
|
|
4
|
+
limit: number;
|
|
5
|
+
remaining: number;
|
|
6
|
+
resetIn: number;
|
|
7
|
+
resetAt: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function checkLimitFast<TRequest>(config: ResolvedConfig<TRequest>, req: TRequest): Promise<FastResult>;
|
|
2
10
|
export declare function checkLimit<TRequest>(config: ResolvedConfig<TRequest>, req: TRequest): Promise<HitLimitResult>;
|
|
3
11
|
//# sourceMappingURL=limiter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limiter.d.ts","sourceRoot":"","sources":["../../src/core/limiter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,cAAc,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"limiter.d.ts","sourceRoot":"","sources":["../../src/core/limiter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,cAAc,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAM7F,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAGD,wBAAsB,cAAc,CAAC,QAAQ,EAC3C,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAChC,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,UAAU,CAAC,CA+BrB;AAGD,wBAAsB,UAAU,CAAC,QAAQ,EACvC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAChC,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,cAAc,CAAC,CAiDzB"}
|
package/dist/core/limiter.js
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
|
-
import { parseWindow
|
|
1
|
+
import { parseWindow } from './utils.js';
|
|
2
2
|
import { buildHeaders } from './headers.js';
|
|
3
3
|
import { buildBody } from './response.js';
|
|
4
|
+
// Optimized check for tiered limits - returns minimal object
|
|
5
|
+
export async function checkLimitFast(config, req) {
|
|
6
|
+
const key = await config.key(req);
|
|
7
|
+
let limit = config.limit;
|
|
8
|
+
let windowMs = config.windowMs;
|
|
9
|
+
if (config.tier && config.tiers) {
|
|
10
|
+
const tierName = await config.tier(req);
|
|
11
|
+
const tierConfig = config.tiers[tierName];
|
|
12
|
+
if (tierConfig) {
|
|
13
|
+
limit = tierConfig.limit;
|
|
14
|
+
if (tierConfig.window) {
|
|
15
|
+
windowMs = parseWindow(tierConfig.window);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (limit === Infinity) {
|
|
20
|
+
return { allowed: true, limit, remaining: Infinity, resetIn: 0, resetAt: 0 };
|
|
21
|
+
}
|
|
22
|
+
const result = await config.store.hit(key, windowMs, limit);
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
return {
|
|
25
|
+
allowed: result.count <= limit,
|
|
26
|
+
limit,
|
|
27
|
+
remaining: Math.max(0, limit - result.count),
|
|
28
|
+
resetIn: Math.max(0, Math.ceil((result.resetAt - now) / 1000)),
|
|
29
|
+
resetAt: result.resetAt
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Original full check - used for testing and backwards compatibility
|
|
4
33
|
export async function checkLimit(config, req) {
|
|
5
|
-
|
|
6
|
-
const key =
|
|
34
|
+
// Use raw key directly - no hashing needed for rate limit keys
|
|
35
|
+
const key = await config.key(req);
|
|
7
36
|
let limit = config.limit;
|
|
8
37
|
let windowMs = config.windowMs;
|
|
9
38
|
let tierName;
|
|
@@ -20,7 +49,7 @@ export async function checkLimit(config, req) {
|
|
|
20
49
|
if (limit === Infinity) {
|
|
21
50
|
return {
|
|
22
51
|
allowed: true,
|
|
23
|
-
info: { limit, remaining: Infinity, resetIn: 0, resetAt: 0, key
|
|
52
|
+
info: { limit, remaining: Infinity, resetIn: 0, resetAt: 0, key, tier: tierName },
|
|
24
53
|
headers: {},
|
|
25
54
|
body: {}
|
|
26
55
|
};
|
|
@@ -35,7 +64,7 @@ export async function checkLimit(config, req) {
|
|
|
35
64
|
remaining,
|
|
36
65
|
resetIn,
|
|
37
66
|
resetAt: result.resetAt,
|
|
38
|
-
key
|
|
67
|
+
key,
|
|
39
68
|
tier: tierName
|
|
40
69
|
};
|
|
41
70
|
return {
|
package/dist/core/limiter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limiter.js","sourceRoot":"","sources":["../../src/core/limiter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"limiter.js","sourceRoot":"","sources":["../../src/core/limiter.ts"],"names":[],"mappings":"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"}
|
package/dist/core/utils.d.ts
CHANGED
package/dist/core/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"AAOA,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAO3D"}
|
package/dist/core/utils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
2
1
|
const UNITS = {
|
|
3
2
|
s: 1000,
|
|
4
3
|
m: 60 * 1000,
|
|
@@ -13,7 +12,4 @@ export function parseWindow(window) {
|
|
|
13
12
|
throw new Error(`Invalid window format: ${window}`);
|
|
14
13
|
return parseInt(match[1]) * UNITS[match[2]];
|
|
15
14
|
}
|
|
16
|
-
export function hashKey(key) {
|
|
17
|
-
return createHash('sha256').update(key).digest('hex').slice(0, 16);
|
|
18
|
-
}
|
|
19
15
|
//# sourceMappingURL=utils.js.map
|
package/dist/core/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK,GAA2B;IACpC,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,EAAE,GAAG,IAAI;IACZ,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI;IACjB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;CACvB,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,MAAuB;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAA;IAE7C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAC9C,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,EAAE,CAAC,CAAA;IAE/D,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AAC7C,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ import type { HitLimitOptions } from '@joint-ops/hitlimit-types';
|
|
|
3
3
|
export type { HitLimitOptions, HitLimitInfo, HitLimitResult, HitLimitStore, StoreResult, TierConfig, HeadersConfig, ResolvedConfig, KeyGenerator, TierResolver, SkipFunction, StoreErrorHandler, ResponseFormatter, ResponseConfig } from '@joint-ops/hitlimit-types';
|
|
4
4
|
export { DEFAULT_LIMIT, DEFAULT_WINDOW, DEFAULT_WINDOW_MS, DEFAULT_MESSAGE } from '@joint-ops/hitlimit-types';
|
|
5
5
|
export { memoryStore } from './stores/memory.js';
|
|
6
|
+
export { checkLimit } from './core/limiter.js';
|
|
6
7
|
export declare function hitlimit(options?: HitLimitOptions<Request>): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAmD,MAAM,2BAA2B,CAAA;AAIjH,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AACrQ,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC7G,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAiB9C,wBAAgB,QAAQ,CAAC,OAAO,GAAE,eAAe,CAAC,OAAO,CAAM,SAgBxC,OAAO,OAAO,QAAQ,QAAQ,YAAY,mBA+GhE"}
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,120 @@
|
|
|
1
1
|
import { resolveConfig } from './core/config.js';
|
|
2
|
-
import { checkLimit } from './core/limiter.js';
|
|
3
2
|
import { memoryStore } from './stores/memory.js';
|
|
4
3
|
export { DEFAULT_LIMIT, DEFAULT_WINDOW, DEFAULT_WINDOW_MS, DEFAULT_MESSAGE } from '@joint-ops/hitlimit-types';
|
|
5
4
|
export { memoryStore } from './stores/memory.js';
|
|
5
|
+
export { checkLimit } from './core/limiter.js';
|
|
6
6
|
function getDefaultKey(req) {
|
|
7
7
|
return req.ip || req.socket?.remoteAddress || 'unknown';
|
|
8
8
|
}
|
|
9
|
+
// Inline response builder for performance
|
|
10
|
+
function buildResponseBody(response, info) {
|
|
11
|
+
if (typeof response === 'function') {
|
|
12
|
+
return response(info);
|
|
13
|
+
}
|
|
14
|
+
return { ...response, limit: info.limit, remaining: info.remaining, resetIn: info.resetIn };
|
|
15
|
+
}
|
|
9
16
|
export function hitlimit(options = {}) {
|
|
10
17
|
const store = options.store ?? memoryStore();
|
|
11
18
|
const config = resolveConfig(options, store, getDefaultKey);
|
|
19
|
+
// Pre-compute flags
|
|
20
|
+
const hasSkip = !!config.skip;
|
|
21
|
+
const hasTiers = !!(config.tier && config.tiers);
|
|
22
|
+
const standardHeaders = config.headers.standard;
|
|
23
|
+
const legacyHeaders = config.headers.legacy;
|
|
24
|
+
const retryAfterHeader = config.headers.retryAfter;
|
|
25
|
+
const limit = config.limit;
|
|
26
|
+
const windowMs = config.windowMs;
|
|
27
|
+
const responseConfig = config.response;
|
|
28
|
+
// Fast path: no skip, no tiers (most common case ~80%)
|
|
29
|
+
if (!hasSkip && !hasTiers) {
|
|
30
|
+
return async (req, res, next) => {
|
|
31
|
+
try {
|
|
32
|
+
const key = await config.key(req);
|
|
33
|
+
const result = await config.store.hit(key, windowMs, limit);
|
|
34
|
+
const allowed = result.count <= limit;
|
|
35
|
+
const remaining = Math.max(0, limit - result.count);
|
|
36
|
+
const resetIn = Math.ceil((result.resetAt - Date.now()) / 1000);
|
|
37
|
+
// Set headers directly
|
|
38
|
+
if (standardHeaders) {
|
|
39
|
+
res.setHeader('RateLimit-Limit', limit);
|
|
40
|
+
res.setHeader('RateLimit-Remaining', remaining);
|
|
41
|
+
res.setHeader('RateLimit-Reset', resetIn);
|
|
42
|
+
}
|
|
43
|
+
if (legacyHeaders) {
|
|
44
|
+
res.setHeader('X-RateLimit-Limit', limit);
|
|
45
|
+
res.setHeader('X-RateLimit-Remaining', remaining);
|
|
46
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil(result.resetAt / 1000));
|
|
47
|
+
}
|
|
48
|
+
if (!allowed) {
|
|
49
|
+
if (retryAfterHeader) {
|
|
50
|
+
res.setHeader('Retry-After', resetIn);
|
|
51
|
+
}
|
|
52
|
+
const body = buildResponseBody(responseConfig, {
|
|
53
|
+
limit, remaining: 0, resetIn, resetAt: result.resetAt, key
|
|
54
|
+
});
|
|
55
|
+
res.status(429).json(body);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
next();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const action = await config.onStoreError(error, req);
|
|
62
|
+
if (action === 'deny') {
|
|
63
|
+
res.status(429).json({ hitlimit: true, message: 'Rate limit error' });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
next();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// Full path: with skip and/or tiers
|
|
12
71
|
return async (req, res, next) => {
|
|
13
|
-
if (
|
|
72
|
+
if (hasSkip) {
|
|
14
73
|
const shouldSkip = await config.skip(req);
|
|
15
74
|
if (shouldSkip) {
|
|
16
75
|
return next();
|
|
17
76
|
}
|
|
18
77
|
}
|
|
19
78
|
try {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
79
|
+
const key = await config.key(req);
|
|
80
|
+
let effectiveLimit = limit;
|
|
81
|
+
let effectiveWindowMs = windowMs;
|
|
82
|
+
let tierName;
|
|
83
|
+
if (hasTiers) {
|
|
84
|
+
tierName = await config.tier(req);
|
|
85
|
+
const tierConfig = config.tiers[tierName];
|
|
86
|
+
if (tierConfig) {
|
|
87
|
+
effectiveLimit = tierConfig.limit;
|
|
88
|
+
if (tierConfig.window) {
|
|
89
|
+
effectiveWindowMs = parseWindow(tierConfig.window);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (effectiveLimit === Infinity) {
|
|
94
|
+
return next();
|
|
95
|
+
}
|
|
96
|
+
const result = await config.store.hit(key, effectiveWindowMs, effectiveLimit);
|
|
97
|
+
const allowed = result.count <= effectiveLimit;
|
|
98
|
+
const remaining = Math.max(0, effectiveLimit - result.count);
|
|
99
|
+
const resetIn = Math.ceil((result.resetAt - Date.now()) / 1000);
|
|
100
|
+
if (standardHeaders) {
|
|
101
|
+
res.setHeader('RateLimit-Limit', effectiveLimit);
|
|
102
|
+
res.setHeader('RateLimit-Remaining', remaining);
|
|
103
|
+
res.setHeader('RateLimit-Reset', resetIn);
|
|
104
|
+
}
|
|
105
|
+
if (legacyHeaders) {
|
|
106
|
+
res.setHeader('X-RateLimit-Limit', effectiveLimit);
|
|
107
|
+
res.setHeader('X-RateLimit-Remaining', remaining);
|
|
108
|
+
res.setHeader('X-RateLimit-Reset', Math.ceil(result.resetAt / 1000));
|
|
109
|
+
}
|
|
110
|
+
if (!allowed) {
|
|
111
|
+
if (retryAfterHeader) {
|
|
112
|
+
res.setHeader('Retry-After', resetIn);
|
|
113
|
+
}
|
|
114
|
+
const body = buildResponseBody(responseConfig, {
|
|
115
|
+
limit: effectiveLimit, remaining: 0, resetIn, resetAt: result.resetAt, key, tier: tierName
|
|
116
|
+
});
|
|
117
|
+
res.status(429).json(body);
|
|
26
118
|
return;
|
|
27
119
|
}
|
|
28
120
|
next();
|
|
@@ -37,4 +129,21 @@ export function hitlimit(options = {}) {
|
|
|
37
129
|
}
|
|
38
130
|
};
|
|
39
131
|
}
|
|
132
|
+
function parseWindow(window) {
|
|
133
|
+
if (typeof window === 'number')
|
|
134
|
+
return window;
|
|
135
|
+
const match = window.match(/^(\d+)(ms|s|m|h|d)$/);
|
|
136
|
+
if (!match)
|
|
137
|
+
return 60000;
|
|
138
|
+
const value = parseInt(match[1], 10);
|
|
139
|
+
const unit = match[2];
|
|
140
|
+
switch (unit) {
|
|
141
|
+
case 'ms': return value;
|
|
142
|
+
case 's': return value * 1000;
|
|
143
|
+
case 'm': return value * 60 * 1000;
|
|
144
|
+
case 'h': return value * 60 * 60 * 1000;
|
|
145
|
+
case 'd': return value * 24 * 60 * 60 * 1000;
|
|
146
|
+
default: return 60000;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
40
149
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAA;AA+D3E,wBAAgB,WAAW,IAAI,aAAa,CAE3C"}
|
package/dist/stores/memory.js
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
class MemoryStore {
|
|
2
2
|
hits = new Map();
|
|
3
|
-
cleanupTimer;
|
|
4
|
-
constructor() {
|
|
5
|
-
this.cleanupTimer = setInterval(() => this.cleanup(), 60000);
|
|
6
|
-
}
|
|
7
3
|
hit(key, windowMs, _limit) {
|
|
8
|
-
const now = Date.now();
|
|
9
4
|
const entry = this.hits.get(key);
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
if (entry !== undefined) {
|
|
6
|
+
// Entry exists and is guaranteed valid (setTimeout hasn't fired yet)
|
|
7
|
+
// Hot path: just increment, no expiration check needed!
|
|
8
|
+
entry.count++;
|
|
9
|
+
return { count: entry.count, resetAt: entry.resetAt };
|
|
14
10
|
}
|
|
15
|
-
entry
|
|
16
|
-
|
|
11
|
+
// New key - create entry with cleanup timeout
|
|
12
|
+
const now = Date.now();
|
|
13
|
+
const resetAt = now + windowMs;
|
|
14
|
+
const timeoutId = setTimeout(() => {
|
|
15
|
+
this.hits.delete(key);
|
|
16
|
+
}, windowMs);
|
|
17
|
+
// Don't keep process alive
|
|
18
|
+
if (typeof timeoutId.unref === 'function') {
|
|
19
|
+
timeoutId.unref();
|
|
20
|
+
}
|
|
21
|
+
this.hits.set(key, { count: 1, resetAt, timeoutId });
|
|
22
|
+
return { count: 1, resetAt };
|
|
17
23
|
}
|
|
18
24
|
reset(key) {
|
|
19
|
-
this.hits.
|
|
25
|
+
const entry = this.hits.get(key);
|
|
26
|
+
if (entry) {
|
|
27
|
+
clearTimeout(entry.timeoutId);
|
|
28
|
+
this.hits.delete(key);
|
|
29
|
+
}
|
|
20
30
|
}
|
|
21
31
|
shutdown() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
cleanup() {
|
|
26
|
-
const now = Date.now();
|
|
27
|
-
for (const [key, entry] of this.hits) {
|
|
28
|
-
if (entry.resetAt <= now) {
|
|
29
|
-
this.hits.delete(key);
|
|
30
|
-
}
|
|
32
|
+
for (const [, entry] of this.hits) {
|
|
33
|
+
clearTimeout(entry.timeoutId);
|
|
31
34
|
}
|
|
35
|
+
this.hits.clear();
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
export function memoryStore() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW;IACE,IAAI,GAAuB,IAAI,GAAG,EAAE,CAAA;IAErD,GAAG,CAAC,GAAW,EAAE,QAAgB,EAAE,MAAc;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAEhC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,qEAAqE;YACrE,wDAAwD;YACxD,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAA;QACvD,CAAC;QAED,8CAA8C;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,OAAO,GAAG,GAAG,GAAG,QAAQ,CAAA;QAE9B,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC,EAAE,QAAQ,CAAC,CAAA;QAEZ,2BAA2B;QAC3B,IAAI,OAAO,SAAS,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YAC1C,SAAS,CAAC,KAAK,EAAE,CAAA;QACnB,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;QACpD,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,GAAW;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,KAAK,EAAE,CAAC;YACV,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;YAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;IAED,QAAQ;QACN,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAC/B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;IACnB,CAAC;CACF;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,WAAW,EAAE,CAAA;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joint-ops/hitlimit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Fast rate limiting middleware for Express, NestJS & Node.js - API throttling, brute force protection, request limiting",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Shayan M Hussain",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"test:watch": "vitest"
|
|
120
120
|
},
|
|
121
121
|
"dependencies": {
|
|
122
|
-
"@joint-ops/hitlimit-types": "
|
|
122
|
+
"@joint-ops/hitlimit-types": "1.0.3"
|
|
123
123
|
},
|
|
124
124
|
"peerDependencies": {
|
|
125
125
|
"@nestjs/common": ">=8.0.0",
|