Add Cloudflare integration adapter with real zone status
Implements testConnection and listResources against the Cloudflare API, reporting the configured zone's real status (active/pending/etc) as a resource. Fixed a bug where non-2xx responses with non-JSON bodies (e.g. invalid zone ID) threw inside the JSON parse instead of failing cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BbJV5nm8KPVH1oNJYKpnoF
This commit is contained in:
parent
527e7dad17
commit
907f5deb5f
2 changed files with 48 additions and 1 deletions
46
backend/src/integrations/cloudflare.ts
Normal file
46
backend/src/integrations/cloudflare.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import type { IntegrationAdapter, Resource } from './types.js'
|
||||||
|
|
||||||
|
interface CloudflareZoneResponse {
|
||||||
|
success: boolean
|
||||||
|
result?: { name: string; status: string }
|
||||||
|
errors?: { message: string }[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cloudflare: IntegrationAdapter = {
|
||||||
|
async testConnection(config, secrets) {
|
||||||
|
const zoneId = config.zoneId
|
||||||
|
const apiKey = secrets.apiKey
|
||||||
|
if (!zoneId) return { ok: false, message: 'Missing zone ID' }
|
||||||
|
if (!apiKey) return { ok: false, message: 'Missing API token' }
|
||||||
|
try {
|
||||||
|
const res = await fetch(`https://api.cloudflare.com/client/v4/zones/${zoneId}`, {
|
||||||
|
headers: { Authorization: `Bearer ${apiKey}` },
|
||||||
|
})
|
||||||
|
if (!res.ok) return { ok: false, message: `HTTP ${res.status}` }
|
||||||
|
const body = (await res.json()) as CloudflareZoneResponse
|
||||||
|
if (!body.success) return { ok: false, message: body.errors?.[0]?.message ?? 'Request failed' }
|
||||||
|
return { ok: true, message: 'Connected' }
|
||||||
|
} catch (err) {
|
||||||
|
return { ok: false, message: err instanceof Error ? err.message : 'Connection failed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async listResources(config, secrets): Promise<Resource[]> {
|
||||||
|
const zoneId = config.zoneId
|
||||||
|
const apiKey = secrets.apiKey
|
||||||
|
if (!zoneId || !apiKey) return []
|
||||||
|
const res = await fetch(`https://api.cloudflare.com/client/v4/zones/${zoneId}`, {
|
||||||
|
headers: { Authorization: `Bearer ${apiKey}` },
|
||||||
|
})
|
||||||
|
if (!res.ok) return []
|
||||||
|
const body = (await res.json()) as CloudflareZoneResponse
|
||||||
|
if (!body.success || !body.result) return []
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: body.result.name,
|
||||||
|
status: body.result.status === 'active' ? 'healthy' : body.result.status === 'pending' || body.result.status === 'initializing' ? 'warning' : 'critical',
|
||||||
|
detail: `Zone status: ${body.result.status}`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import { uptimeKuma } from './uptimeKuma.js'
|
||||||
import { docker } from './docker.js'
|
import { docker } from './docker.js'
|
||||||
import { proxmox } from './proxmox.js'
|
import { proxmox } from './proxmox.js'
|
||||||
import { netbird } from './netbird.js'
|
import { netbird } from './netbird.js'
|
||||||
|
import { cloudflare } from './cloudflare.js'
|
||||||
|
|
||||||
const notImplemented: IntegrationAdapter = {
|
const notImplemented: IntegrationAdapter = {
|
||||||
async testConnection() {
|
async testConnection() {
|
||||||
|
|
@ -15,7 +16,7 @@ export const adapterRegistry: Record<IntegrationType, IntegrationAdapter> = {
|
||||||
docker,
|
docker,
|
||||||
proxmox,
|
proxmox,
|
||||||
netbird,
|
netbird,
|
||||||
cloudflare: notImplemented,
|
cloudflare,
|
||||||
aws: notImplemented,
|
aws: notImplemented,
|
||||||
weather: notImplemented,
|
weather: notImplemented,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue