Skip to main content
Glama

Smart-AI-Bridge

rate-limiter.jsโ€ข3.87 kB
/** * Rate Limiter Module * Prevents abuse through request throttling */ export class RateLimiter { constructor(options = {}) { this.limits = { perMinute: options.perMinute || 60, perHour: options.perHour || 500, perDay: options.perDay || 5000 }; this.counters = { perMinute: new Map(), perHour: new Map(), perDay: new Map() }; // Cleanup intervals setInterval(() => this.cleanup('perMinute'), 60 * 1000); setInterval(() => this.cleanup('perHour'), 60 * 60 * 1000); setInterval(() => this.cleanup('perDay'), 24 * 60 * 60 * 1000); } /** * Check if request is allowed * @param {string} identifier - Client identifier (token, IP, etc.) * @returns {object} - { allowed: boolean, retryAfter: number|null } */ checkLimit(identifier) { const now = Date.now(); // Check each time window for (const [window, limit] of Object.entries(this.limits)) { const counter = this.counters[window]; const key = `${identifier}:${this.getWindowKey(now, window)}`; const count = counter.get(key) || 0; if (count >= limit) { return { allowed: false, retryAfter: this.getRetryAfter(window, now), limit, window }; } } // Increment counters this.increment(identifier, now); return { allowed: true }; } /** * Increment request counters */ increment(identifier, now = Date.now()) { for (const window of Object.keys(this.limits)) { const counter = this.counters[window]; const key = `${identifier}:${this.getWindowKey(now, window)}`; counter.set(key, (counter.get(key) || 0) + 1); } } /** * Get window key for timestamp */ getWindowKey(timestamp, window) { const date = new Date(timestamp); switch (window) { case 'perMinute': case 'minute': return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-${date.getHours()}-${date.getMinutes()}`; case 'perHour': case 'hour': return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-${date.getHours()}`; case 'perDay': case 'day': return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; default: return timestamp; } } /** * Calculate retry-after seconds */ getRetryAfter(window, now) { const date = new Date(now); switch (window) { case 'perMinute': case 'minute': return 60 - date.getSeconds(); case 'perHour': case 'hour': return (60 - date.getMinutes()) * 60 - date.getSeconds(); case 'perDay': case 'day': return (24 - date.getHours()) * 3600 - date.getMinutes() * 60 - date.getSeconds(); default: return 60; } } /** * Cleanup old counters */ cleanup(window) { const counter = this.counters[window]; const now = Date.now(); const currentKey = this.getWindowKey(now, window); for (const key of counter.keys()) { if (!key.endsWith(currentKey)) { counter.delete(key); } } } /** * Get usage statistics */ getStats(identifier) { const now = Date.now(); const stats = {}; for (const [window, limit] of Object.entries(this.limits)) { const counter = this.counters[window]; const key = `${identifier}:${this.getWindowKey(now, window)}`; const count = counter.get(key) || 0; stats[window] = { used: count, limit, remaining: Math.max(0, limit - count), percentage: Math.round((count / limit) * 100) }; } return stats; } } // Singleton instance export const rateLimiter = new RateLimiter({ perMinute: 60, // 60 requests per minute perHour: 500, // 500 requests per hour perDay: 5000 // 5000 requests per day });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Platano78/Smart-AI-Bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server