UNPKG

cx-client

Version:

Cloudonix CLI tool for managing accounts and resources

293 lines (267 loc) 10.9 kB
const axios = require('axios'); const { debug } = require('./debug'); const API_BASE_URL = 'https://api.cloudonix.io'; /** * Creates an API client with the given API key * @param {string} apiKey - The API key to use for authentication * @returns {Object} The API client */ const createApiClient = (apiKey) => { const client = axios.create({ baseURL: API_BASE_URL, headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' } }); // Add request interceptor for debugging client.interceptors.request.use(request => { debug(`REQUEST: ${request.method.toUpperCase()} ${request.baseURL}${request.url}`, { headers: request.headers, data: request.data }); return request; }); // Add response interceptor for debugging client.interceptors.response.use( response => { debug(`RESPONSE: ${response.status} ${response.statusText}`, { data: response.data, headers: response.headers }); // Ensure timestamps in log entries are preserved in full ISO format if (response.data && response.data.log && Array.isArray(response.data.log)) { // Ensure each log entry has a properly formatted timestamp response.data.log.forEach(entry => { // Fix both timestamp and time fields ['timestamp', 'time'].forEach(field => { if (entry[field]) { // Check if it's a truncated timestamp const value = entry[field]; // Make sure it's a valid Date object for proper serialization try { // Handle truncated timestamps by adding missing parts if needed let dateString = value; // If it's truncated like "2025-04-01T02", append missing parts if (/^\d{4}-\d{2}-\d{2}T\d{2}$/.test(dateString)) { dateString += ':00:00.000Z'; // Add missing minutes, seconds } else if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(dateString)) { dateString += ':00.000Z'; // Add missing seconds } else if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(dateString)) { dateString += '.000Z'; // Add missing milliseconds } const date = new Date(dateString); if (!isNaN(date.getTime())) { entry[field] = date.toISOString(); } } catch (e) { // Ignore conversion errors and keep original } } }); }); } return response; }, error => { if (error.response) { debug(`ERROR RESPONSE: ${error.response.status} ${error.response.statusText}`, { data: error.response.data, headers: error.response.headers }); } else if (error.request) { debug('ERROR: No response received', { request: error.request }); } else { debug('ERROR: Request setup failed', { message: error.message }); } return Promise.reject(error); } ); return client; }; /** * Validates a domain by attempting to fetch it * @param {string} domain - The domain name to validate * @param {string} apiKey - The API key for authentication * @returns {Promise<boolean>} Whether the domain is valid */ const validateDomain = async (domain, apiKey) => { try { debug(`Validating domain '${domain}'`); const client = createApiClient(apiKey); const response = await client.get(`/customers/self/domains/${domain}`); return response.status === 200; } catch (error) { if (error.response) { console.error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { console.error(`Network Error: Unable to reach Cloudonix API`); } else { console.error(`Error: ${error.message}`); } return false; } }; /** * Gets detailed information about a domain * @param {string} domain - The domain name to fetch * @param {string} apiKey - The API key for authentication * @returns {Promise<Object>} The domain information */ const getDomainInfo = async (domain, apiKey) => { try { debug(`Fetching information for domain '${domain}'`); const client = createApiClient(apiKey); const response = await client.get(`/customers/self/domains/${domain}`); return response.data; } catch (error) { if (error.response) { throw new Error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { throw new Error(`Network Error: Unable to reach Cloudonix API`); } else { throw new Error(`Error: ${error.message}`); } } }; /** * Gets detailed information about a call session * @param {string} domain - The domain name * @param {string} sessionId - The session ID to fetch * @param {string} apiKey - The API key for authentication * @returns {Promise<Object>} The session information */ const getSessionInfo = async (domain, sessionId, apiKey) => { try { debug(`Fetching information for session '${sessionId}' in domain '${domain}'`); const client = createApiClient(apiKey); const response = await client.get(`/customers/self/domains/${domain}/sessions/${sessionId}`); return response.data; } catch (error) { if (error.response) { throw new Error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { throw new Error(`Network Error: Unable to reach Cloudonix API`); } else { throw new Error(`Error: ${error.message}`); } } }; /** * Gets detailed information about a domain's subscribers * @param {string} domain - The domain name * @param {string} apiKey - The API key for authentication * @param {string} [subscriberId] - Optional subscriber ID to fetch a specific subscriber * @returns {Promise<Object>} The subscriber information */ const getSubscriberInfo = async (domain, apiKey, subscriberId = null) => { try { debug(`Fetching subscriber information for domain '${domain}'${subscriberId ? ` and subscriber '${subscriberId}'` : ' (all subscribers)'}`); const client = createApiClient(apiKey); // Build the URL based on whether we're fetching a specific subscriber or all subscribers const url = subscriberId ? `/customers/self/domains/${domain}/subscribers/${subscriberId}` : `/customers/self/domains/${domain}/subscribers`; const response = await client.get(url); return response.data; } catch (error) { if (error.response) { throw new Error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { throw new Error(`Network Error: Unable to reach Cloudonix API`); } else { throw new Error(`Error: ${error.message}`); } } }; /** * Gets detailed information about a domain's applications * @param {string} domain - The domain name * @param {string} apiKey - The API key for authentication * @param {string} [applicationId] - Optional application ID to fetch a specific application * @returns {Promise<Object>} The application information */ const getApplicationInfo = async (domain, apiKey, applicationId = null) => { try { debug(`Fetching application information for domain '${domain}'${applicationId ? ` and application '${applicationId}'` : ' (all applications)'}`); const client = createApiClient(apiKey); // Build the URL based on whether we're fetching a specific application or all applications const url = applicationId ? `/customers/self/domains/${domain}/applications/${applicationId}` : `/customers/self/domains/${domain}/applications`; const response = await client.get(url); return response.data; } catch (error) { if (error.response) { throw new Error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { throw new Error(`Network Error: Unable to reach Cloudonix API`); } else { throw new Error(`Error: ${error.message}`); } } }; /** * Gets detailed information about a domain's trunks * @param {string} domain - The domain name * @param {string} apiKey - The API key for authentication * @param {string} [trunkId] - Optional trunk ID to fetch a specific trunk * @returns {Promise<Object>} The trunk information */ const getTrunkInfo = async (domain, apiKey, trunkId = null) => { try { debug(`Fetching trunk information for domain '${domain}'${trunkId ? ` and trunk '${trunkId}'` : ' (all trunks)'}`); const client = createApiClient(apiKey); // Build the URL based on whether we're fetching a specific trunk or all trunks const url = trunkId ? `/customers/self/domains/${domain}/trunks/${trunkId}` : `/customers/self/domains/${domain}/trunks`; const response = await client.get(url); return response.data; } catch (error) { if (error.response) { throw new Error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { throw new Error(`Network Error: Unable to reach Cloudonix API`); } else { throw new Error(`Error: ${error.message}`); } } }; /** * Gets detailed information about a domain's DNIDs * @param {string} domain - The domain name * @param {string} apiKey - The API key for authentication * @param {string} [dnidId] - Optional DNID ID to fetch a specific DNID * @returns {Promise<Object>} The DNID information */ const getDnidInfo = async (domain, apiKey, dnidId = null) => { try { debug(`Fetching DNID information for domain '${domain}'${dnidId ? ` and DNID '${dnidId}'` : ' (all DNIDs)'}`); const client = createApiClient(apiKey); // Build the URL based on whether we're fetching a specific DNID or all DNIDs const url = dnidId ? `/customers/self/domains/${domain}/dnids/${dnidId}` : `/customers/self/domains/${domain}/dnids`; const response = await client.get(url); return response.data; } catch (error) { if (error.response) { throw new Error(`API Error: ${error.response.status} - ${error.response.data.message || error.response.statusText}`); } else if (error.request) { throw new Error(`Network Error: Unable to reach Cloudonix API`); } else { throw new Error(`Error: ${error.message}`); } } }; module.exports = { createApiClient, validateDomain, getDomainInfo, getSessionInfo, getSubscriberInfo, getApplicationInfo, getTrunkInfo, getDnidInfo };