Skip to main content
Glama
RateLimiter.ts2.72 kB
export class RateLimiter { private requestTimestamps: number[] = []; private maxRequestsPerWindow: number; private windowMs: number; private isWaiting: boolean = false; private waitQueue: Array<() => void> = []; constructor(maxRequestsPerWindow: number, windowMs: number = 60000) { this.maxRequestsPerWindow = maxRequestsPerWindow; this.windowMs = windowMs; } async fetch(url: string | URL, options?: RequestInit): Promise<Response> { await this.acquireToken(); try { return await fetch(url, options); } catch (error) { // For certain errors like network failures, don't count against rate limit if (error instanceof TypeError) { this.releaseToken(); // Remove the timestamp we added } throw error; } } private async acquireToken(): Promise<void> { // Clean up old timestamps outside the window const now = Date.now(); this.requestTimestamps = this.requestTimestamps.filter( timestamp => now - timestamp < this.windowMs, ); // Check if we're at the limit if (this.requestTimestamps.length >= this.maxRequestsPerWindow) { // Calculate how long to wait const oldestTimestamp = this.requestTimestamps[0]; const timeToWait = this.windowMs - (now - oldestTimestamp); if (timeToWait > 0) { console.error(`Rate limit reached. Waiting ${timeToWait}ms before next request`); await this.waitInQueue(timeToWait); // After waiting, try again (recursive call) to ensure we're still under the limit return this.acquireToken(); } } // Add current timestamp to the list this.requestTimestamps.push(now); } private releaseToken(): void { // Remove the most recent timestamp if (this.requestTimestamps.length > 0) { this.requestTimestamps.pop(); } } private async waitInQueue(ms: number): Promise<void> { return new Promise<void>((resolve) => { if (this.isWaiting) { this.waitQueue.push(resolve); return; } this.isWaiting = true; setTimeout(() => { this.isWaiting = false; resolve(); // Process all eligible requests in the queue while ( this.waitQueue.length > 0 && this.requestTimestamps.length < this.maxRequestsPerWindow ) { const next = this.waitQueue.shift(); if (next) next(); } }, ms); }); } } /** * Create and export a singleton instance for Art Institute of Chicago API * * Limited to 60 requests per minute per their documentation * https://api.artic.edu/docs/#authentication */ export const articRateLimiter = new RateLimiter(60, 60000);

Latest Blog Posts

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/mikechao/artic-mcp'

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