// engine/runtime-security/rate-limiter.ts — SPEC-084 AC-06
// Token bucket rate limiting per tool name, in-memory only.
// Tool categories for rate limiting
const READ_TOOLS = new Set([
    'list_specs',
    'validate',
    'check_readiness',
    'security_report',
    'audit_spec',
    'estimate',
    'semantic_search',
    'list_groups',
    'license_status',
    'usage_stats',
    'usage_report',
    'spec_history',
]);
const DESTRUCTIVE_TOOLS = new Set(['delete_spec', 'delete_project', 'empty_trash']);
const buckets = new Map();
function getToolCategory(toolName) {
    if (DESTRUCTIVE_TOOLS.has(toolName)) {
        return 'destructive';
    }
    if (READ_TOOLS.has(toolName)) {
        return 'read';
    }
    return 'write';
}
function getRateLimitConfig(toolName, config) {
    const category = getToolCategory(toolName);
    return config.rateLimits[category];
}
function computeRefill(bucket, rlConfig, now) {
    const elapsed = (now - bucket.lastRefill) / 1000;
    const refilled = elapsed * rlConfig.refillRatePerSecond;
    return {
        tokens: Math.min(rlConfig.maxTokens, bucket.tokens + refilled),
        lastRefill: now,
    };
}
function isBurstActive(bucket, rlConfig, now) {
    if (bucket.burstStart === null) {
        return false;
    }
    return now - bucket.burstStart < rlConfig.burstDurationMs;
}
export function checkRateLimit(toolName, config, now) {
    const currentTime = now ?? Date.now();
    const rlConfig = getRateLimitConfig(toolName, config);
    const existing = buckets.get(toolName);
    const bucket = existing ?? {
        tokens: rlConfig.maxTokens,
        lastRefill: currentTime,
        burstStart: null,
    };
    // Refill tokens
    const refill = computeRefill(bucket, rlConfig, currentTime);
    // Check burst allowance
    const effectiveMax = isBurstActive(bucket, rlConfig, currentTime)
        ? rlConfig.maxTokens * rlConfig.burstMultiplier
        : rlConfig.maxTokens;
    let tokens = Math.min(refill.tokens, effectiveMax);
    let burstStart = bucket.burstStart;
    if (tokens >= 1) {
        tokens -= 1;
        // Activate burst if near empty (below 20% of max)
        if (tokens < rlConfig.maxTokens * 0.2 && burstStart === null) {
            burstStart = currentTime;
        }
        buckets.set(toolName, { tokens, lastRefill: refill.lastRefill, burstStart });
        return {
            allowed: true,
            retryAfterMs: 0,
            remainingTokens: Math.floor(tokens),
        };
    }
    buckets.set(toolName, { tokens, lastRefill: refill.lastRefill, burstStart });
    // Calculate retry time
    const tokensNeeded = 1 - tokens;
    const retryAfterMs = Math.ceil((tokensNeeded / rlConfig.refillRatePerSecond) * 1000);
    return {
        allowed: false,
        retryAfterMs,
        remainingTokens: 0,
    };
}
/** Reset all rate limit state (for testing) */
export function resetRateLimits() {
    buckets.clear();
}
//# sourceMappingURL=rate-limiter.js.map