UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

135 lines (134 loc) 4.14 kB
/** * Token Storage for OAuth 2.1 authentication * Provides implementations for storing OAuth tokens */ import { logger } from "../../utils/logger.js"; /** * In-memory token storage implementation * Suitable for development and single-session use * Tokens are lost when the process terminates */ export class InMemoryTokenStorage { tokens = new Map(); async getTokens(serverId) { return this.tokens.get(serverId) ?? null; } async saveTokens(serverId, tokens) { this.tokens.set(serverId, tokens); } async deleteTokens(serverId) { this.tokens.delete(serverId); } async hasTokens(serverId) { return this.tokens.has(serverId); } async clearAll() { this.tokens.clear(); } /** * Get the number of stored token sets */ get size() { return this.tokens.size; } /** * Get all server IDs with stored tokens */ getServerIds() { return Array.from(this.tokens.keys()); } } /** * File-based token storage implementation * Persists tokens to disk for cross-session use */ export class FileTokenStorage { filePath; tokens = new Map(); loaded = false; constructor(filePath) { this.filePath = filePath; } async loadTokens() { if (this.loaded) { return; } try { const fs = await import("fs/promises"); const data = await fs.readFile(this.filePath, "utf-8"); const parsed = JSON.parse(data); this.tokens = new Map(Object.entries(parsed)); this.loaded = true; } catch (error) { // File doesn't exist or is invalid, start with empty tokens if (error instanceof Error && "code" in error && error.code !== "ENOENT") { logger.warn(`[FileTokenStorage] Error loading tokens: ${error.message}`); } this.tokens = new Map(); this.loaded = true; } } async saveToFile() { try { const fs = await import("fs/promises"); const path = await import("path"); // Ensure directory exists const dir = path.dirname(this.filePath); await fs.mkdir(dir, { recursive: true }); // Write tokens to file const data = Object.fromEntries(this.tokens.entries()); await fs.writeFile(this.filePath, JSON.stringify(data, null, 2), "utf-8"); } catch (error) { logger.error(`[FileTokenStorage] Error saving tokens: ${error instanceof Error ? error.message : String(error)}`); throw error; } } async getTokens(serverId) { await this.loadTokens(); return this.tokens.get(serverId) ?? null; } async saveTokens(serverId, tokens) { await this.loadTokens(); this.tokens.set(serverId, tokens); await this.saveToFile(); } async deleteTokens(serverId) { await this.loadTokens(); this.tokens.delete(serverId); await this.saveToFile(); } async hasTokens(serverId) { await this.loadTokens(); return this.tokens.has(serverId); } async clearAll() { this.tokens.clear(); await this.saveToFile(); } } /** * Check if tokens are expired or about to expire * @param tokens - OAuth tokens to check * @param bufferSeconds - Buffer time in seconds before expiration (default: 60) * @returns True if tokens are expired or will expire within buffer time */ export function isTokenExpired(tokens, bufferSeconds = 60) { if (!tokens.expiresAt) { return false; // No expiration set, assume valid } const bufferMs = bufferSeconds * 1000; const now = Date.now(); return tokens.expiresAt - bufferMs <= now; } /** * Calculate token expiration timestamp from expires_in value * @param expiresIn - Token lifetime in seconds * @returns Expiration timestamp (Unix epoch in milliseconds) */ export function calculateExpiresAt(expiresIn) { return Date.now() + expiresIn * 1000; }