tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
306 lines (185 loc) β’ 6.94 kB
Markdown
# π§ `TinyRateLimiter` β A Simple Per-User Rate Limiter
The `TinyRateLimiter` is a flexible and lightweight JavaScript class designed to help you limit actions (like requests or commands) per user. You can define rules like **maximum hits**, **time windows**, and benefit from automatic memory cleanup. β¨
## π¦ Constructor
```js
new TinyRateLimiter(options)
```
### π§ Options
| Option | Type | Default | Description |
| ----------------- | -------- | ----------- | ---------------------------------------------- |
| `maxHits` | `number` | `undefined` | Max number of hits per user before blocking π§ |
| `interval` | `number` | `undefined` | Time window in milliseconds β±οΈ |
| `cleanupInterval` | `number` | `undefined` | Interval to auto-clean inactive users π§Ή |
| `maxIdle` | `number` | `300000` | Max idle time per user before cleanup π€ |
| `maxMemory` | `number` | `100000` | Max memory size limit before auto cleanup π§ |
> β οΈ At least one of `maxHits` or `interval` must be defined.
## π Methods
### π `hit(userId: string): void`
Registers a hit for the given `userId`.
```js
rateLimiter.hit("user123");
```
Tracks timestamps internally and automatically removes old entries based on `interval` and `maxHits`.
### β `isRateLimited(userId: string): boolean`
Checks if the given `userId` is currently rate limited.
```js
if (rateLimiter.isRateLimited("user123")) {
console.log("Too many actions! Please slow down.");
}
```
### π§Ύ `isGroupId(id: string): boolean`
Checks whether a given `id` is marked as a **groupId** (i.e., it represents a group and not a single user).
```js
if (rateLimiter.isGroupId('group-xyz')) {
console.log('This is a group ID!');
}
```
### π οΈ `setData(userId: string, timestamps: number[]): void`
Sets the hit timestamps for a specific user. Useful for restoring or mocking state.
```js
rateLimiter.setData("user123", [Date.now() - 1000, Date.now()]);
```
### π₯ `getData(userId: string): number[]`
Returns all hit timestamps for a given user.
```js
const hits = rateLimiter.getData("user123");
console.log(hits); // [timestamp1, timestamp2, ...]
```
### π§ `getMaxHits(): number`
Returns the configured `maxHits` value, or throws if invalid.
### β³ `getInterval(): number`
Returns the configured `interval` value, or throws if invalid.
### π `getLastHit(userId: string): number|null`
Returns the timestamp of the user's last hit, or `null` if none.
### β `getTimeSinceLastHit(userId: string): number|null`
Returns how much time (in ms) has passed since the user's last hit.
### π `getAverageHitSpacing(userId: string): number|null`
Returns the average time (in ms) between a user's hits, or `null` if not enough data.
### π `getGroupId(userId: string): string`
Returns the group ID that the user is assigned to (default is same as userId).
### π¦ `assignToGroup(userId: string, groupId: string): void`
Manually assigns a user to a specific group for shared rate limits.
### π‘ `getGroupTTL(groupId: string): number|undefined`
Returns the custom TTL (ms) for a specific group, if defined.
### π°οΈ `setGroupTTL(groupId: string, ttl: number): void`
Sets the maximum idle time before a group is auto-cleaned.
### π `getMetrics(groupId: string): { totalHits, lastHit, timeSinceLastHit, averageHitSpacing }`
Returns a detailed summary of activity for a group:
```js
{
totalHits: number,
lastHit: number|null,
timeSinceLastHit: number|null,
averageHitSpacing: number|null
}
```
### π§Ό `destroy(): void`
Stops internal timers and clears all stored data. Ideal for cleanup in tests or long-running apps.
### π§ `setOnMemoryExceeded(callback: () => void): void`
Sets a callback to be called when memory usage (based on internal data size) exceeds a threshold.
```js
rateLimiter.setOnMemoryExceeded(() => {
console.warn("Rate limiter memory usage is high!");
});
```
### π§½ `clearOnMemoryExceeded(): void`
Clears the memory-exceeded callback.
### π `setOnGroupExpired(callback: (groupId: string) => void): void`
Sets a callback that will be called whenever a group expires due to inactivity (based on TTL or `maxIdle`).
```js
rateLimiter.setOnGroupExpired((groupId) => {
console.log(`Group "${groupId}" has expired.`);
});
```
### π `clearOnGroupExpired(): void`
Removes the group expiration callback.
### β `deleteGroupTTL(groupId: string): void`
Removes any custom TTL (idle timeout) for a specific group.
```js
rateLimiter.deleteGroupTTL("admins");
```
### β»οΈ `resetGroup(groupId: string): void`
Removes all hit history and data for a group (but keeps userβgroup associations unless manually removed).
### π€ `resetUserGroup(userId: string): void`
Fully removes a user's data about group assignment.
### π `hasData(userId: string): boolean`
Returns `true` if the user has any stored data (hits or group association).
### π₯ `getUsersInGroup(groupId: string): string[]`
Returns a list of users assigned to the given group.
### π€ `getMaxIdle(): number`
Returns the current global `maxIdle` value (in ms) used for cleanup.
### π€ `setMaxIdle(ms: number): void`
Sets the global `maxIdle` value (in ms), which applies to all groups without a custom TTL.
### π `getTotalHits(groupId: string): number`
Returns the total number of hits recorded for a given group.
```js
const total = rateLimiter.getTotalHits("group42");
console.log(`Group total hits: ${total}`);
```
## π§½ Automatic Cleanup
Inactive groups are automatically removed every `cleanupInterval` milliseconds if they haven't had any hits for longer than their TTL (or `maxIdle` if not set).
This helps reduce memory usage and keeps your limiter lean and clean! πͺΆ
## π₯ Errors
The constructor will throw if:
* Neither `maxHits` nor `interval` are provided.
* Any of the values are not positive integers.
## π§ͺ Example Usage
```js
const limiter = new TinyRateLimiter({
maxHits: 5,
interval: 10000,
cleanupInterval: 60000,
maxIdle: 120000,
maxMemory: 100000,
});
limiter.hit("user42");
if (limiter.isRateLimited("user42")) {
console.log("Rate limited! π");
} else {
console.log("Action allowed β
");
}
```
## π Summary
| Feature | Support |
| -------------------------- | ------- |
| Per-user tracking | β
|
| Max hits | β
|
| Time window interval | β
|
| Automatic cleanup | β
|
| Manual data control | β
|
| Lightweight + fast | β
|
| Group-based rate limiting | β
|
| Activity metrics per group | β
|