import { Agent } from 'undici' import type { IntegrationAdapter, Resource } from './types.js' interface ProxmoxResourceEntry { type: string name?: string status?: string vmid?: number node?: string } function authHeader(apiKey: string): Record { return { Authorization: `PVEAPIToken=${apiKey}` } } // Proxmox ships with a self-signed cert by default, which Node's fetch rejects out of the box. const insecureDispatcher = new Agent({ connect: { rejectUnauthorized: false } }) export const proxmox: IntegrationAdapter = { async testConnection(config, secrets) { const baseUrl = config.baseUrl?.replace(/\/$/, '') const apiKey = secrets.apiKey if (!baseUrl) return { ok: false, message: 'Missing baseUrl' } if (!apiKey) return { ok: false, message: 'Missing API token' } try { const res = await fetch(`${baseUrl}/api2/json/version`, { headers: authHeader(apiKey), dispatcher: insecureDispatcher, } as RequestInit) if (!res.ok) return { ok: false, message: `HTTP ${res.status}` } return { ok: true, message: 'Connected' } } catch (err) { return { ok: false, message: err instanceof Error ? err.message : 'Connection failed' } } }, async listResources(config, secrets): Promise { const baseUrl = config.baseUrl?.replace(/\/$/, '') const apiKey = secrets.apiKey if (!baseUrl || !apiKey) return [] const res = await fetch(`${baseUrl}/api2/json/cluster/resources?type=vm`, { headers: authHeader(apiKey), dispatcher: insecureDispatcher, } as RequestInit) if (!res.ok) return [] const body = (await res.json()) as { data: ProxmoxResourceEntry[] } return body.data.map((entry) => ({ name: entry.name ?? `vm-${entry.vmid}`, status: entry.status === 'running' ? 'healthy' : entry.status === 'stopped' ? 'unknown' : 'warning', detail: `${entry.type} on ${entry.node} — ${entry.status}`, })) }, }