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

271 lines (270 loc) 9.77 kB
/** * NeuroLink OAuth Token Store * * Secure storage for OAuth tokens with encoding support and multi-provider capability. * Stores tokens in the user's home directory with restrictive permissions. * * Features: * - Multi-provider token storage in a single tokens.json file * - Secure file storage with 0o600 permissions * - Token expiration checking with configurable buffer * - Simple XOR-based obfuscation (not encryption, but not plaintext) * - Automatic token refresh via configurable refresher functions * - Cross-platform support (Unix/macOS/Windows) */ import type { StoredOAuthTokens, TokenRefresher } from "../types/index.js"; /** * Secure token storage for OAuth tokens with multi-provider support * * Provides persistent storage for OAuth tokens with: * - Multi-provider support in a single file * - Secure file permissions (0o600) * - Optional obfuscation/encoding * - Token expiration checking with buffer * - Automatic token refresh via configurable refreshers * * @example * ```typescript * const store = new TokenStore(); * * // Save tokens for a provider * await store.saveTokens("anthropic", { * accessToken: "sk-...", * refreshToken: "rt-...", * expiresAt: Date.now() + 3600000, * tokenType: "Bearer", * }); * * // Set up automatic refresh * store.setTokenRefresher("anthropic", async (refreshToken) => { * // Call OAuth refresh endpoint * return newTokens; * }); * * // Get a valid token (auto-refreshes if needed) * const token = await store.getValidToken("anthropic"); * ``` */ export declare class TokenStore { private static readonly STORAGE_VERSION; private static readonly NEUROLINK_DIR; private static readonly TOKEN_FILE; private static readonly FILE_PERMISSIONS; private static readonly DIR_PERMISSIONS; /** Default expiration buffer: 1 hour (proactive refresh before actual expiry) */ private static readonly DEFAULT_EXPIRY_BUFFER_MS; private readonly storagePath; private readonly encryptionEnabled; private readonly encryptionKey; private readonly tokenRefreshers; private readonly inFlightRefreshes; private readonly _mutex; /** * Creates a new TokenStore instance * * @param options - Configuration options * @param options.encryptionEnabled - Whether to enable token obfuscation (default: true) * @param options.customStoragePath - Override the default storage path */ constructor(options?: { encryptionEnabled?: boolean; customStoragePath?: string; }); /** * Gets the path where tokens are stored * * @returns The absolute path to the token storage file */ getStoragePath(): string; /** * Saves OAuth tokens for a specific provider * * @param provider - The provider name (e.g., "anthropic", "openai") * @param tokens - The OAuth tokens to save * @throws TokenStoreError if storage fails */ saveTokens(provider: string, tokens: StoredOAuthTokens): Promise<void>; /** * Internal save without mutex — callers must already hold the mutex. */ private _saveTokensInternal; /** * Loads stored OAuth tokens for a specific provider * * @param provider - The provider name (e.g., "anthropic", "openai") * @returns The stored tokens, or null if not found * @throws TokenStoreError if reading fails (other than file not found) */ loadTokens(provider: string): Promise<StoredOAuthTokens | null>; /** * Internal load without mutex — callers must already hold the mutex. */ private _loadTokensInternal; /** * Clears stored tokens for a specific provider * * @param provider - The provider name (e.g., "anthropic", "openai") * @throws TokenStoreError if deletion fails */ clearTokens(provider: string): Promise<void>; private _clearTokensImpl; /** * Checks if the given tokens are expired * * @param tokens - The OAuth tokens to check * @param bufferMs - Buffer time in milliseconds before actual expiration (default: 5 minutes) * @returns true if token is expired or will expire within buffer time */ isTokenExpired(tokens: StoredOAuthTokens, bufferMs?: number): boolean; /** * Gets a valid access token for a provider, refreshing if needed * * If the stored token is expired or about to expire, and a refresher * function has been set, it will automatically refresh the token. * * @param provider - The provider name (e.g., "anthropic", "openai") * @returns The valid access token, or null if not available * @throws TokenStoreError if refresh fails */ getValidToken(provider: string): Promise<string | null>; private _getValidTokenImpl; /** * Sets the token refresher function for a provider * * The refresher function will be called automatically when getValidToken * detects that the stored token is expired or about to expire. * * @param provider - The provider name (e.g., "anthropic", "openai") * @param refresher - Function that takes a refresh token and returns new tokens */ setTokenRefresher(provider: string, refresher: TokenRefresher): void; /** * Removes the token refresher function for a provider * * @param provider - The provider name (e.g., "anthropic", "openai") */ clearTokenRefresher(provider: string): void; /** * Checks if tokens exist for a specific provider * * @param provider - The provider name (e.g., "anthropic", "openai") * @returns true if tokens are stored for the provider */ hasTokens(provider: string): Promise<boolean>; /** * Lists all providers that have stored tokens * * @returns Array of provider names */ listProviders(): Promise<string[]>; /** * Lists all provider keys that start with the given prefix * * @param prefix - The prefix to filter by (e.g., "anthropic:") * @returns Array of matching provider keys */ listByPrefix(prefix: string): Promise<string[]>; /** * Marks a provider's tokens as permanently disabled (persisted to disk). * * Disabled accounts are skipped immediately by consumers — no wasted * round-trips. The state survives proxy restarts because it is stored * alongside the tokens in the JSON file. * * @param provider - The provider key (e.g., "anthropic:user@example.com") * @param reason - Optional human-readable reason (e.g., "refresh_failed") */ markDisabled(provider: string, reason?: string): Promise<void>; /** * Re-enables a previously disabled provider (persisted to disk). * * Clears the disabled flag, timestamp, and reason so the account can * be used again by the proxy pool. * * @param provider - The provider key (e.g., "anthropic:user@example.com") */ markEnabled(provider: string): Promise<void>; /** * Checks whether a provider's tokens are currently disabled. * * Returns false for providers that don't exist in the store (no tokens * at all) and for entries that predate the disabled field (backward compat). * * @param provider - The provider key * @returns true if the provider entry exists and is disabled */ isDisabled(provider: string): Promise<boolean>; /** * Lists all provider keys that are currently disabled. * * @returns Array of disabled provider keys (empty if none or no storage file) */ listDisabled(): Promise<string[]>; /** * Removes expired and unrefreshable token entries from disk. * * An entry is pruned when: * - Its access token is expired (with optional buffer) AND it has no * refresh token, AND it is NOT manually disabled. * * Manually disabled entries are preserved so that `auth enable` can * re-enable them later. They are only removed via explicit `clearTokens`. * * @param bufferMs - Extra buffer in milliseconds to subtract from expiresAt * when checking expiry (default: 0 — strict expiry check) * @returns Array of provider keys that were removed */ pruneExpired(bufferMs?: number): Promise<string[]>; /** * Clears all stored tokens for all providers * * @throws TokenStoreError if deletion fails */ clearAllTokens(): Promise<void>; /** * Loads the storage data from file */ private loadStorageData; /** * Saves storage data to file */ private saveStorageData; /** * Deletes the storage file */ private deleteStorageFile; /** * Validates token structure */ private validateTokens; /** * Ensures the storage directory exists with proper permissions */ private ensureDirectory; /** * Derives an encoding key from machine-specific information * This provides basic obfuscation - for production use, consider * using proper encryption with a user-provided key or system keychain */ private deriveEncryptionKey; /** * Simple XOR-based obfuscation * Note: This is NOT cryptographically secure, just basic obfuscation * For production use, consider using node:crypto with proper encryption */ private obfuscate; /** * Reverses the XOR obfuscation */ private deobfuscate; } /** * Default token store singleton instance * Uses default configuration with encryption enabled */ export declare const tokenStore: TokenStore; /** * Alias for backward compatibility * @deprecated Use tokenStore instead */ export declare const defaultTokenStore: TokenStore;