wulf-pulse/app/api/openclaw/datto-rmm/sites/route.ts
lorentz 679fe3871c feat: add OpenClaw read-only Datto RMM API endpoints
GET /api/openclaw/datto-rmm/sites
GET /api/openclaw/datto-rmm/devices         (filters: siteUid, online, deleted, page, limit)
GET /api/openclaw/datto-rmm/devices/[uid]
GET /api/openclaw/datto-rmm/devices/[uid]/audit  (always live)
GET /api/openclaw/datto-rmm/alerts          (filters: resolved, siteUid, deviceUid, limit)
GET /api/openclaw/datto-rmm/alerts/open

- All protected by x-openclaw-key header
- Default: queries Pulse DB (datto_rmm_devices/alerts/sites tables)
- ?live=true: proxies to Datto RMM API via DattoRMMClient
- Responses include source:'db'|'live' for data freshness awareness
2026-03-21 17:45:19 -04:00

51 lines
1.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { validateOpenClawKey } from '@/lib/utils/openclaw-auth';
import { Pool } from 'pg';
import { getDattoRMMClient } from '@/lib/services/datto-rmm-factory';
const pool = new Pool({
host: process.env.POSTGRES_HOST,
port: parseInt(process.env.POSTGRES_PORT || '5432'),
database: process.env.POSTGRES_DB,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
});
export async function GET(request: NextRequest) {
const authError = validateOpenClawKey(request);
if (authError) return authError;
const live = request.nextUrl.searchParams.get('live') === 'true';
try {
if (live) {
const client = getDattoRMMClient();
const sites = await client.getAllSites();
return NextResponse.json({
data: sites,
total: sites.length,
source: 'live',
});
}
const result = await pool.query(`
SELECT
id, uid, name, description, notes, on_demand,
autotask_company_id, autotask_company_name,
number_of_devices, number_of_online_devices, number_of_offline_devices,
portal_url, synced_at, updated_at
FROM datto_rmm_sites
ORDER BY name
`);
return NextResponse.json({
data: result.rows,
total: result.rowCount,
source: 'db',
synced_at: result.rows[0]?.synced_at ?? null,
});
} catch (error) {
const msg = error instanceof Error ? error.message : String(error);
return NextResponse.json({ error: msg }, { status: 500 });
}
}