/* Single SigNoz API client module for alert rule and channel management (RFC-0342). No dashboard management. No user management. RFC-0342: initial implementation. */ export interface SignozApiClientConfig { apiUrl: string; apiToken: string; } export interface SignozAlertRule { id: string; name: string; severity: string; promql?: string; builder?: unknown; evalWindow: string; forDuration: string; condition: { op: string; target: number }; channels: string[]; labels?: Record; description: string; } export interface SignozChannel { id: string; kind: string; target: string[]; } export interface SignozApplyPlan { rules: { create: SignozAlertRule[]; update: SignozAlertRule[]; delete: string[]; }; channels: { create: SignozChannel[]; update: SignozChannel[]; delete: string[]; }; } export interface SignozApiClient { listManagedRules(): Promise; listManagedChannels(): Promise; createRule(rule: SignozAlertRule): Promise; updateRule(rule: SignozAlertRule): Promise; deleteRule(id: string): Promise; createChannel(channel: SignozChannel): Promise; updateChannel(channel: SignozChannel): Promise; deleteChannel(id: string): Promise; } export function createSignozApiClient(config: SignozApiClientConfig): SignozApiClient { const headers: Record = { "Content-Type": "application/json", Authorization: `Bearer ${config.apiToken}`, }; async function apiCall(path: string, options: RequestInit = {}): Promise { const url = `${config.apiUrl}/api${path}`; const response = await fetch(url, { ...options, headers: { ...headers, ...(options.headers as Record) }, }); if (!response.ok) { throw new Error(`SigNoz API ${path} returned ${response.status}: ${await response.text()}`); } if (response.status === 204) return null; return response.json(); } return { async listManagedRules(): Promise { const data = (await apiCall("/alerts/rules")) as { data?: SignozAlertRule[] }; const rules = data?.data ?? []; return rules.filter((r) => r.labels?.managed_by === "warpgogol"); }, async listManagedChannels(): Promise { const data = (await apiCall("/alerts/channels")) as { data?: SignozChannel[] }; const channels = data?.data ?? []; return channels.filter((c) => c.id.startsWith("warpgogol-")); }, async createRule(rule: SignozAlertRule): Promise { await apiCall("/alerts/rules", { method: "POST", body: JSON.stringify({ ...rule, labels: { ...rule.labels, managed_by: "warpgogol" } }), }); }, async updateRule(rule: SignozAlertRule): Promise { await apiCall(`/alerts/rules/${rule.id}`, { method: "PUT", body: JSON.stringify({ ...rule, labels: { ...rule.labels, managed_by: "warpgogol" } }), }); }, async deleteRule(id: string): Promise { await apiCall(`/alerts/rules/${id}`, { method: "DELETE" }); }, async createChannel(channel: SignozChannel): Promise { await apiCall("/alerts/channels", { method: "POST", body: JSON.stringify({ ...channel, id: `warpgogol-${channel.id}` }), }); }, async updateChannel(channel: SignozChannel): Promise { await apiCall(`/alerts/channels/warpgogol-${channel.id}`, { method: "PUT", body: JSON.stringify(channel), }); }, async deleteChannel(id: string): Promise { await apiCall(`/alerts/channels/warpgogol-${id}`, { method: "DELETE" }); }, }; }