/** * ConcurrentLimiter: Acquire a slot with expiring lock * KEYS[1] = limiter key (ZSET of lockId -> expireTime) * ARGV[1] = max concurrent * ARGV[2] = lock ID (unique per request) * ARGV[3] = current time (seconds) * ARGV[4] = lock timeout (seconds) * Returns: [allowed (0/1), current count, retry_after] */ export declare const LUA_CONCURRENT_ACQUIRE = "\nlocal key = KEYS[1]\nlocal max_concurrent = tonumber(ARGV[1])\nlocal lock_id = ARGV[2]\nlocal now = tonumber(ARGV[3])\nlocal lock_timeout = tonumber(ARGV[4])\n\n-- Remove expired locks\nredis.call(\"ZREMRANGEBYSCORE\", key, \"-inf\", now)\n\n-- Check current count\nlocal current = redis.call(\"ZCARD\", key)\nif current < max_concurrent then\n -- Add lock with expiration time as score\n local expire_at = now + lock_timeout\n redis.call(\"ZADD\", key, expire_at, lock_id)\n redis.call(\"EXPIRE\", key, lock_timeout + 10)\n return {1, current + 1, 0}\nend\n\n-- Get time until next slot frees up\nlocal oldest = redis.call(\"ZRANGE\", key, 0, 0, \"WITHSCORES\")\nlocal retry_after = 0\nif oldest[2] then\n retry_after = math.max(0, tonumber(oldest[2]) - now)\nend\nreturn {0, current, retry_after}\n"; /** * ConcurrentLimiter: Release a lock * KEYS[1] = limiter key * ARGV[1] = lock ID */ export declare const LUA_CONCURRENT_RELEASE = "\nredis.call(\"ZREM\", KEYS[1], ARGV[1])\nreturn 1\n"; /** * BucketLimiter: Increment counter at time boundary * KEYS[1] = limiter key * ARGV[1] = max count * ARGV[2] = current bucket timestamp (boundary) * ARGV[3] = TTL seconds * Returns: [allowed (0/1), current count, seconds until reset] */ export declare const LUA_BUCKET_ACQUIRE = "\nlocal key = KEYS[1]\nlocal max_count = tonumber(ARGV[1])\nlocal bucket_ts = ARGV[2]\nlocal ttl = tonumber(ARGV[3])\n\n-- Use hash: field is bucket timestamp, value is count\nlocal current = tonumber(redis.call(\"HGET\", key, bucket_ts) or \"0\")\n\nif current < max_count then\n redis.call(\"HINCRBY\", key, bucket_ts, 1)\n redis.call(\"EXPIRE\", key, ttl)\n -- Clean old buckets\n local fields = redis.call(\"HKEYS\", key)\n for _, f in ipairs(fields) do\n if f ~= bucket_ts then\n redis.call(\"HDEL\", key, f)\n end\n end\n return {1, current + 1, 0}\nend\n\nreturn {0, current, ttl}\n"; /** * WindowLimiter: Sliding window using sorted set * KEYS[1] = limiter key (ZSET of request timestamps) * ARGV[1] = max count * ARGV[2] = window size (seconds) * ARGV[3] = current time (seconds, with decimals) * ARGV[4] = request ID (unique) * Returns: [allowed (0/1), current count, retry_after] */ export declare const LUA_WINDOW_ACQUIRE = "\nlocal key = KEYS[1]\nlocal max_count = tonumber(ARGV[1])\nlocal window_size = tonumber(ARGV[2])\nlocal now = tonumber(ARGV[3])\nlocal request_id = ARGV[4]\n\nlocal window_start = now - window_size\n\n-- Remove entries outside window\nredis.call(\"ZREMRANGEBYSCORE\", key, \"-inf\", window_start)\n\n-- Count entries in window\nlocal current = redis.call(\"ZCARD\", key)\n\nif current < max_count then\n redis.call(\"ZADD\", key, now, request_id)\n redis.call(\"EXPIRE\", key, math.ceil(window_size) + 1)\n return {1, current + 1, 0}\nend\n\n-- Calculate retry_after based on oldest entry\nlocal oldest = redis.call(\"ZRANGE\", key, 0, 0, \"WITHSCORES\")\nlocal retry_after = 0\nif oldest[2] then\n retry_after = math.max(0, (tonumber(oldest[2]) + window_size) - now)\nend\nreturn {0, current, retry_after}\n"; //# sourceMappingURL=lua-scripts.d.ts.map