Skip to main content
Glama
config.js3.88 kB
import { program } from 'commander'; import dotenv from 'dotenv'; import winston from 'winston'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); dotenv.config(); export const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() ) }) ] }); export class Config { constructor() { this.credentials = null; this.sessionTokens = null; this.tokenExpiryTime = null; } parseArguments() { program .option('--api-key <key>', 'IG API Key') .option('--identifier <id>', 'IG Account Identifier') .option('--password <pwd>', 'IG Account Password') .option('--demo <boolean>', 'Use demo account', 'true') .option('--config <path>', 'Path to config file') .parse(process.argv); const options = program.opts(); if (options.config) { this.loadFromFile(options.config); } else { this.loadFromArgsOrEnv(options); } this.validateCredentials(); return this; } loadFromFile(configPath) { try { const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); this.credentials = { apiKey: config.apiKey, identifier: config.identifier, password: config.password, isDemo: config.demo !== false }; } catch (error) { logger.error(`Failed to load config file: ${error.message}`); throw error; } } loadFromArgsOrEnv(options) { this.credentials = { apiKey: options.apiKey || process.env.IG_API_KEY, identifier: options.identifier || process.env.IG_IDENTIFIER, password: options.password || process.env.IG_PASSWORD, isDemo: (options.demo || process.env.IG_DEMO || 'true').toLowerCase() === 'true' }; } validateCredentials() { const missing = []; if (!this.credentials.apiKey) missing.push('API Key (--api-key or IG_API_KEY)'); if (!this.credentials.identifier) missing.push('Identifier (--identifier or IG_IDENTIFIER)'); if (!this.credentials.password) missing.push('Password (--password or IG_PASSWORD)'); if (missing.length > 0) { const errorMsg = `Missing required credentials: ${missing.join(', ')}`; logger.error(errorMsg); throw new Error(errorMsg); } logger.info(`Using ${this.credentials.isDemo ? 'DEMO' : 'LIVE'} environment`); } getApiUrl() { // Default to demo if credentials not yet set if (!this.credentials) { return 'https://demo-api.ig.com'; } return this.credentials.isDemo ? 'https://demo-api.ig.com' : 'https://api.ig.com'; } setSessionTokens(tokens) { this.sessionTokens = { xSecurityToken: tokens['x-security-token'], cst: tokens.cst, lightstreamerEndpoint: tokens.lightstreamerEndpoint, currentAccountId: tokens.currentAccountId }; this.tokenExpiryTime = Date.now() + (12 * 60 * 60 * 1000); // 12 hours logger.info('Session tokens updated'); } getSessionTokens() { if (!this.sessionTokens) { throw new Error('No active session. Please login first.'); } if (this.isTokenExpired()) { throw new Error('Session tokens expired. Please login again.'); } return this.sessionTokens; } isTokenExpired() { return this.tokenExpiryTime && Date.now() > this.tokenExpiryTime; } clearSessionTokens() { this.sessionTokens = null; this.tokenExpiryTime = null; logger.info('Session tokens cleared'); } } export const config = new Config();

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/kea0811/ig-trading-mcp'

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