Skip to main content
Glama

WhaTap MXQL CLI

by devload
WhatapClient.ts8.15 kB
/** * WhatapClient - WhaTap API Client * * Handles API requests to WhaTap service with authentication */ import axios, { AxiosInstance } from 'axios'; import type { MxqlRequest, MxqlParams, WhaTapResponse, Project, QueryOptions, } from '../types'; import { ApiError } from '../types'; import { AuthManager } from '../auth/AuthManager'; /** * WhatapClient handles API calls to WhaTap service */ export class WhatapClient { private axios: AxiosInstance; private authManager: AuthManager; private serviceUrl: string; constructor(authManager: AuthManager) { this.authManager = authManager; const session = authManager.getSession(); this.serviceUrl = session.serviceUrl; // Create axios instance (no need for separate cookie jar - we'll use cookies from AuthManager) this.axios = axios.create({ baseURL: this.serviceUrl, timeout: 30000, headers: { 'Content-Type': 'application/json; charset=UTF-8', 'Accept': 'application/json, text/plain, */*', 'User-Agent': 'WhatapMxqlCLI/1.0.0', }, withCredentials: true, validateStatus: (status) => true, // Accept all status codes (like mobile app) }); // Add request interceptor to inject API token this.axios.interceptors.request.use( (config) => { const session = this.authManager.getSession(); if (session.apiToken) { config.headers['x-whatap-token'] = session.apiToken; } return config; }, (error) => Promise.reject(error) ); } /** * Execute MXQL query * * @param options - Query options * @returns Query result * @throws {ApiError} If API call fails */ async executeMxql(options: QueryOptions): Promise<WhaTapResponse> { const { pcode, mql, stime, etime, limit } = options; // Build MXQL request const mxqlRequest: MxqlRequest = { type: 'mxql', pcode, params: { mql, stime: stime || Date.now() - 3600000, // Default: 1 hour ago etime: etime || Date.now(), limit: limit || 100, }, path: 'text', }; try { // MXQL API requires cookie authentication (not API token) const cookieHeader = this.authManager.getCookieHeader(); const response = await this.axios.post<any>( '/yard/api/flush', mxqlRequest, { headers: { Cookie: cookieHeader, }, } ); return { code: response.status, msg: response.statusText, data: response.data, ok: response.status === 200, }; } catch (error: any) { if (axios.isAxiosError(error)) { throw new ApiError( `MXQL execution failed: ${error.message}`, error.response?.status, error.response?.data ); } throw new ApiError( `MXQL execution failed: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Get list of projects for the authenticated user * * @returns List of projects * @throws {ApiError} If API call fails */ async getProjects(): Promise<Project[]> { try { const response = await this.axios.get<any>('/open/api/json/projects'); if (response.status !== 200) { throw new ApiError( `Failed to get projects: ${response.statusText}`, response.status, response.data ); } // Open API returns { data: Project[], total: number } return response.data.data || response.data; } catch (error: any) { if (axios.isAxiosError(error)) { throw new ApiError( `Failed to get projects: ${error.message}`, error.response?.status, error.response?.data ); } throw new ApiError( `Failed to get projects: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Get project details by project code * * @param pcode - Project code * @returns Project details * @throws {ApiError} If API call fails */ async getProject(pcode: number): Promise<Project> { try { // Get all projects and find the matching one // (Open API doesn't have a single project endpoint) const projects = await this.getProjects(); const project = projects.find((p) => p.projectCode === pcode); if (!project) { throw new ApiError( `Project with code ${pcode} not found`, 404 ); } return project; } catch (error: any) { if (error instanceof ApiError) { throw error; } if (axios.isAxiosError(error)) { throw new ApiError( `Failed to get project: ${error.message}`, error.response?.status, error.response?.data ); } throw new ApiError( `Failed to get project: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Execute generic GET request * * @param url - API endpoint URL * @returns Response data * @throws {ApiError} If API call fails */ async get<T = any>(url: string): Promise<WhaTapResponse<T>> { try { const response = await this.axios.get<T>(url); return { code: response.status, msg: response.statusText, data: response.data, ok: response.status === 200, }; } catch (error: any) { if (axios.isAxiosError(error)) { throw new ApiError( `GET request failed: ${error.message}`, error.response?.status, error.response?.data ); } throw new ApiError( `GET request failed: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Execute generic POST request * * @param url - API endpoint URL * @param data - Request body * @returns Response data * @throws {ApiError} If API call fails */ async post<T = any>(url: string, data?: any): Promise<WhaTapResponse<T>> { try { const response = await this.axios.post<T>(url, data); return { code: response.status, msg: response.statusText, data: response.data, ok: response.status === 200, }; } catch (error: any) { if (axios.isAxiosError(error)) { throw new ApiError( `POST request failed: ${error.message}`, error.response?.status, error.response?.data ); } throw new ApiError( `POST request failed: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } /** * Get list of available categories for a project * * @param pcode - Project code * @param stime - Start time (Unix timestamp in milliseconds) * @param etime - End time (Unix timestamp in milliseconds) * @returns List of available categories * @throws {ApiError} If API call fails */ async getCategories(pcode: number, stime?: number, etime?: number): Promise<WhaTapResponse> { const now = Date.now(); const request = { type: 'tagcount', pcode, params: { stime: stime || now - 3600000, // Default: 1 hour ago etime: etime || now, }, path: 'categories', }; try { // Categories API requires cookie authentication const cookieHeader = this.authManager.getCookieHeader(); const response = await this.axios.post<any>( '/yard/api/flush', request, { headers: { Cookie: cookieHeader, }, } ); return { code: response.status, msg: response.statusText, data: response.data, ok: response.status === 200, }; } catch (error: any) { if (axios.isAxiosError(error)) { throw new ApiError( `Failed to get categories: ${error.message}`, error.response?.status, error.response?.data ); } throw new ApiError( `Failed to get categories: ${error instanceof Error ? error.message : 'Unknown error'}` ); } } }

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/devload/whatap-mxql-cli'

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