Skip to main content
Glama
credentials.ts3.55 kB
/** * Credentials File Handler * Manages reading and writing configuration and credentials to a separate file */ import fs from 'fs/promises'; import path from 'path'; export interface Config { ACCESS_TOKEN: string; REFRESH_TOKEN: string; EMAIL: string; } export class CredentialsManager { private static instance: CredentialsManager; private credentialsFilePath: string; private cachedConfig: Config | null = null; private constructor() { // Get credentials file path from environment variable // Default to .getoutpost_credentials.json in user's home directory const defaultPath = path.join( process.env.HOME || process.env.USERPROFILE || process.cwd(), '.getoutpost_credentials.json' ); this.credentialsFilePath = process.env.CREDENTIALS_FILE_PATH || defaultPath; console.error("credentialsFilePath = ", this.credentialsFilePath) } /** * Get singleton instance */ static getInstance(): CredentialsManager { if (!CredentialsManager.instance) { CredentialsManager.instance = new CredentialsManager(); } return CredentialsManager.instance; } /** * Load configuration from the file */ async loadConfig(): Promise<Config> { try { await fs.access(this.credentialsFilePath); const content = await fs.readFile(this.credentialsFilePath, 'utf-8'); const config = JSON.parse(content); // Validate required fields if (!config.ACCESS_TOKEN || !config.REFRESH_TOKEN || !config.EMAIL) { throw new Error('Invalid credentials file: missing required fields (ACCESS_TOKEN, REFRESH_TOKEN, EMAIL)'); } this.cachedConfig = config; return config; } catch (error: any) { if (error.code === 'ENOENT') { throw new Error(`Credentials file not found at ${this.credentialsFilePath}. Please create it with required fields.`); } throw new Error(`Failed to load configuration: ${error.message}`); } } /** * Get cached config or load if not cached */ async getConfig(): Promise<Config> { if (this.cachedConfig) { return this.cachedConfig; } return await this.loadConfig(); } /** * Save configuration to the file */ async saveConfig(config: Config): Promise<void> { try { // Ensure directory exists const dir = path.dirname(this.credentialsFilePath); await fs.mkdir(dir, { recursive: true }); // Write configuration with nice formatting await fs.writeFile( this.credentialsFilePath, JSON.stringify(config, null, 2), 'utf-8' ); this.cachedConfig = config; console.error(`[Credentials] Successfully saved configuration to ${this.credentialsFilePath}`); } catch (error: any) { throw new Error(`Failed to save configuration: ${error.message}`); } } /** * Update tokens in the credentials file */ async updateTokens(accessToken: string, refreshToken: string): Promise<void> { try { // Load existing configuration const config = await this.getConfig(); // Update tokens config.ACCESS_TOKEN = accessToken; config.REFRESH_TOKEN = refreshToken; // Save back to file await this.saveConfig(config); console.error('[Credentials] Successfully updated tokens'); } catch (error: any) { throw new Error(`Failed to update tokens: ${error.message}`); } } /** * Get the credentials file path */ getCredentialsFilePath(): string { return this.credentialsFilePath; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aoutpost2-rgb/getoutpost-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server