UNPKG

breathe-api

Version:

Model Context Protocol server for Breathe HR APIs with Swagger/OpenAPI support - also works with custom APIs

122 lines 3.3 kB
import PQueue from 'p-queue'; const RATE_LIMITS = { api_request: { concurrency: 3, interval: 1000, intervalCap: 5, timeout: 30000, }, parse_swagger: { concurrency: 5, interval: 1000, intervalCap: 10, timeout: 60000, }, explain_api_feature: { concurrency: 4, interval: 1000, intervalCap: 8, timeout: 45000, }, generate_api_client: { concurrency: 2, interval: 1000, intervalCap: 3, timeout: 120000, }, cache_stats: { concurrency: 10, interval: 1000, intervalCap: 100, }, clear_cache: { concurrency: 10, interval: 1000, intervalCap: 20, }, }; const rateLimiters = new Map(); export function getToolRateLimiter(toolName) { if (!rateLimiters.has(toolName)) { const config = RATE_LIMITS[toolName] || { concurrency: 5, interval: 1000, intervalCap: 10, }; const queue = new PQueue({ concurrency: config.concurrency, interval: config.interval, intervalCap: config.intervalCap, timeout: config.timeout, throwOnTimeout: true, }); rateLimiters.set(toolName, queue); } return rateLimiters.get(toolName); } export function isToolRateLimited(toolName) { const limiter = rateLimiters.get(toolName); if (!limiter) return false; const config = RATE_LIMITS[toolName]; if (!config) return false; return limiter.pending >= config.concurrency || limiter.size > 0; } export function getToolRateLimitStatus(toolName) { const limiter = rateLimiters.get(toolName); const config = RATE_LIMITS[toolName] || { concurrency: 5, intervalCap: 10, }; if (!limiter) { return { pending: 0, queued: 0, concurrency: config.concurrency, intervalCap: config.intervalCap, isLimited: false, }; } return { pending: limiter.pending, queued: limiter.size, concurrency: config.concurrency, intervalCap: config.intervalCap, isLimited: isToolRateLimited(toolName), }; } export function getAllRateLimitStatus() { const status = {}; for (const toolName of Object.keys(RATE_LIMITS)) { status[toolName] = getToolRateLimitStatus(toolName); } for (const toolName of rateLimiters.keys()) { if (!status[toolName]) { status[toolName] = getToolRateLimitStatus(toolName); } } return status; } export function resetToolRateLimiter(toolName) { const limiter = rateLimiters.get(toolName); if (limiter) { limiter.clear(); } } export function resetAllRateLimiters() { for (const limiter of rateLimiters.values()) { limiter.clear(); } } export class RateLimitError extends Error { toolName; limitType; constructor(toolName, limitType, message) { super(message || `Rate limit exceeded for tool: ${toolName} (${limitType})`); this.toolName = toolName; this.limitType = limitType; this.name = 'RateLimitError'; } } //# sourceMappingURL=rate-limiter.js.map