UNPKG

@kya-os/mcp-i

Version:

The TypeScript MCP framework with identity features built-in

57 lines (56 loc) 1.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedisNonceCache = void 0; /** * Redis-based nonce cache implementation * Suitable for multi-instance deployments */ class RedisNonceCache { redis; // Redis client - type depends on redis library used keyPrefix; constructor(redis, keyPrefix = "mcpi:nonce:") { this.redis = redis; this.keyPrefix = keyPrefix; } getKey(nonce, agentDid) { if (agentDid) { return `${this.keyPrefix}${agentDid}:${nonce}`; } return `${this.keyPrefix}${nonce}`; } async has(nonce, agentDid) { try { const key = this.getKey(nonce, agentDid); const exists = await this.redis.exists(key); return exists === 1; } catch (error) { console.error("Redis has() operation failed:", error); throw new Error(`Failed to check nonce existence: ${error}`); } } async add(nonce, ttl, agentDid) { try { const key = this.getKey(nonce, agentDid); // Use SET with NX (not exists) and EX (expiry) for atomic add-if-absent // This is truly atomic in Redis const result = await this.redis.set(key, "1", "EX", ttl, "NX"); if (result !== "OK") { throw new Error(`Nonce ${nonce} already exists - potential replay attack`); } } catch (error) { // Re-throw our own errors if (error.message?.includes("already exists")) { throw error; } console.error("Redis add() operation failed:", error); throw new Error(`Failed to add nonce to cache: ${error}`); } } async cleanup() { // Redis handles expiry automatically, so this is a no-op // This method exists to satisfy the interface } } exports.RedisNonceCache = RedisNonceCache;