import * as https from 'https'; import * as fs from 'fs'; import { config } from '../config'; interface VespaRequestOptions { method?: string; headers?: Record; body?: string; } export async function vespaRequest(url: string, options: VespaRequestOptions = {}): Promise { return new Promise((resolve, reject) => { const urlObj = new URL(url); const httpsOptions: https.RequestOptions = { hostname: urlObj.hostname, port: 443, path: urlObj.pathname + urlObj.search, method: options.method || 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', ...options.headers } }; // Add certificate authentication if available if (config.vespaCertPath && config.vespaKeyPath) { try { httpsOptions.cert = fs.readFileSync(config.vespaCertPath); httpsOptions.key = fs.readFileSync(config.vespaKeyPath); httpsOptions.rejectUnauthorized = false; } catch (error) { console.error('Failed to load certificates:', error); } } const req = https.request(httpsOptions, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { try { resolve({ ok: true, status: res.statusCode, json: async () => JSON.parse(data), text: async () => data }); } catch (error) { reject(error); } } else if (res.statusCode === 504) { // Handle timeout as success if we got data try { const parsed = JSON.parse(data); if (parsed.root && parsed.root.children) { resolve({ ok: false, // Keep ok: false for proper handling status: res.statusCode, json: async () => parsed, text: async () => data }); } else { resolve({ ok: false, status: res.statusCode, text: async () => data }); } } catch (error) { resolve({ ok: false, status: res.statusCode, text: async () => data }); } } else { resolve({ ok: false, status: res.statusCode, text: async () => data }); } }); }); req.on('error', (error) => { reject(error); }); if (options.body) { req.write(options.body); } req.end(); }); }