UNPKG

obsidian-mcp-server

Version:

Obsidian Knowledge-Management MCP (Model Context Protocol) server that enables AI agents and development tools to interact with an Obsidian vault. It provides a comprehensive suite of tools for reading, writing, searching, and managing notes, tags, and fr

157 lines (156 loc) 6.26 kB
/** * @fileoverview Provides a generic rate limiter class to manage request rates * based on configurable time windows and request counts. It supports custom * key generation, periodic cleanup of expired entries, and skipping rate * limiting in development environments. * @module src/utils/security/rateLimiter */ import { RequestContext } from "../internal/index.js"; /** * Configuration options for the {@link RateLimiter}. */ export interface RateLimitConfig { /** Time window in milliseconds during which requests are counted. */ windowMs: number; /** Maximum number of requests allowed from a single key within the `windowMs`. */ maxRequests: number; /** * Custom error message template when rate limit is exceeded. * Use `{waitTime}` as a placeholder for the remaining seconds until reset. * Defaults to "Rate limit exceeded. Please try again in {waitTime} seconds." */ errorMessage?: string; /** * If `true`, rate limiting checks will be skipped if `process.env.NODE_ENV` is 'development'. * Defaults to `false`. */ skipInDevelopment?: boolean; /** * An optional function to generate a unique key for rate limiting based on an identifier * and optional request context. If not provided, the raw identifier is used as the key. * @param identifier - The base identifier (e.g., IP address, user ID). * @param context - Optional request context. * @returns A string to be used as the rate limiting key. */ keyGenerator?: (identifier: string, context?: RequestContext) => string; /** * Interval in milliseconds for cleaning up expired rate limit entries from memory. * Defaults to 5 minutes. Set to `0` or `null` to disable automatic cleanup. */ cleanupInterval?: number | null; } /** * Represents an individual entry in the rate limiter's tracking store. * @internal */ export interface RateLimitEntry { /** The current count of requests within the window. */ count: number; /** The timestamp (milliseconds since epoch) when the current window resets. */ resetTime: number; } /** * A generic rate limiter class that can be used to control the frequency of * operations or requests from various sources. It stores request counts in memory. */ export declare class RateLimiter { private limits; private cleanupTimer; private currentConfig; /** * Default configuration values for the rate limiter. */ private static DEFAULT_CONFIG; /** * Creates a new `RateLimiter` instance. * @param {Partial<RateLimitConfig>} [initialConfig={}] - Optional initial configuration * to override default settings. */ constructor(initialConfig?: Partial<RateLimitConfig>); /** * Starts the periodic cleanup timer for expired rate limit entries. * If a timer already exists, it's cleared and restarted. * @private */ private startCleanupTimer; /** * Removes expired entries from the rate limit store to free up memory. * This method is called periodically by the cleanup timer. * @private */ private cleanupExpiredEntries; /** * Updates the rate limiter's configuration. * @param {Partial<RateLimitConfig>} newConfig - Partial configuration object * with new settings to apply. */ configure(newConfig: Partial<RateLimitConfig>): void; /** * Retrieves a copy of the current rate limiter configuration. * @returns {RateLimitConfig} The current configuration. */ getConfig(): RateLimitConfig; /** * Resets all rate limits, clearing all tracked keys and their counts. * @param {RequestContext} [context] - Optional context for logging the reset operation. */ reset(context?: RequestContext): void; /** * Checks if a request identified by a key exceeds the configured rate limit. * If the limit is exceeded, an `McpError` is thrown. * * @param {string} identifier - A unique string identifying the source of the request * (e.g., IP address, user ID, session ID). * @param {RequestContext} [context] - Optional request context for logging and potentially * for use by a custom `keyGenerator`. * @throws {McpError} If the rate limit is exceeded for the given key. * The error will have `BaseErrorCode.RATE_LIMITED`. */ check(identifier: string, context?: RequestContext): void; /** * Retrieves the current rate limit status for a given key. * @param {string} key - The rate limit key (as generated by `keyGenerator` or the raw identifier). * @returns {{ current: number; limit: number; remaining: number; resetTime: number } | null} * An object with current status, or `null` if the key is not currently tracked (or has expired). * `resetTime` is a Unix timestamp (milliseconds). */ getStatus(key: string): { current: number; limit: number; remaining: number; resetTime: number; } | null; /** * Stops the cleanup timer and clears all rate limit entries. * This should be called if the rate limiter instance is no longer needed, * to prevent resource leaks (though `unref` on the timer helps). * @param {RequestContext} [context] - Optional context for logging the disposal. */ dispose(context?: RequestContext): void; } /** * A default, shared instance of the `RateLimiter`. * This instance is configured with default settings (e.g., 100 requests per 15 minutes). * It can be reconfigured using `rateLimiter.configure()`. * * Example: * ```typescript * import { rateLimiter, RequestContext } from './rateLimiter'; * import { requestContextService } from '../internal'; * * const context: RequestContext = requestContextService.createRequestContext({ operation: 'MyApiCall' }); * const userIp = '123.45.67.89'; * * try { * rateLimiter.check(userIp, context); * // Proceed with operation * } catch (e) { * if (e instanceof McpError && e.code === BaseErrorCode.RATE_LIMITED) { * console.error("Rate limit hit:", e.message); * } else { * // Handle other errors * } * } * ``` */ export declare const rateLimiter: RateLimiter;