Files
LaunchPad/apps/backend/src/db/repositories/apis.ts

78 lines
2.4 KiB
TypeScript

import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm";
import { db } from "../client.js";
import { detectedApis } from "../schema.js";
export interface DetectedApiEntry {
id: string;
serviceId: string;
path: string;
type: string;
status: number;
detectedAt: string;
}
function mapRow(row: typeof detectedApis.$inferSelect): DetectedApiEntry {
return {
id: row.id,
serviceId: row.serviceId,
path: row.path,
type: row.type,
status: row.status,
detectedAt: row.detectedAt,
};
}
export function listDetectedApis(): DetectedApiEntry[] {
return db.select().from(detectedApis).all().map(mapRow);
}
export function getApisForService(serviceId: string): DetectedApiEntry[] {
return db.select().from(detectedApis).where(eq(detectedApis.serviceId, serviceId)).all().map(mapRow);
}
/**
* Ersetzt die gespeicherten API-Funde eines Dienstes komplett durch die
* neuen Ergebnisse eines Scan-Laufs - kein Anhäufen von veralteten
* Einträgen, wenn sich z. B. der API-Pfad einer Software mal ändert.
*
* Liefert zusätzlich `added` zurück: die Einträge, die VORHER noch nicht
* gespeichert waren (nach Pfad+Typ verglichen) - damit der Scanner auf der
* Scanner-Seite nach dem ersten Mal nur noch NEUE/geänderte Funde anzeigen
* kann, statt bei jedem erneuten Scan die komplette (meist unveränderte)
* Liste erneut runterzurattern. Die vollständige Liste bleibt jederzeit
* unter Admin -> APIs einsehbar.
*/
export function replaceApisForService(
serviceId: string,
found: { path: string; type: string; status: number }[]
): { saved: DetectedApiEntry[]; added: DetectedApiEntry[] } {
const before = getApisForService(serviceId);
const beforeKeys = new Set(before.map((e) => `${e.path}::${e.type}`));
db.delete(detectedApis).where(eq(detectedApis.serviceId, serviceId)).run();
const timestamp = new Date().toISOString();
const rows = found.map((f) => ({
id: randomUUID(),
serviceId,
path: f.path,
type: f.type,
status: f.status,
detectedAt: timestamp,
}));
if (rows.length > 0) {
db.insert(detectedApis).values(rows).run();
}
const saved = rows.map(mapRow);
const added = saved.filter((e) => !beforeKeys.has(`${e.path}::${e.type}`));
return { saved, added };
}
export function deleteApisForService(serviceId: string): void {
db.delete(detectedApis).where(eq(detectedApis.serviceId, serviceId)).run();
}