Files
govoplan-audit/webui/src/api/audit.ts
T

116 lines
3.6 KiB
TypeScript

import { apiFetch, type ApiSettings, type DeltaDeletedItem } from "@govoplan/core-webui";
export type AuditAdminItem = {
id: string;
scope: "tenant" | "system";
tenant_id?: string | null;
actor_email?: string | null;
action: string;
object_type?: string | null;
object_id?: string | null;
details: Record<string, unknown>;
created_at: string;
};
export type AuditSortBy = "time" | "actor" | "action" | "object" | "tenant";
export type AuditQueryOptions = {
tenantId?: string | null;
allTenants?: boolean;
scope?: "tenant" | "system";
limit?: number;
offset?: number;
page?: number;
pageSize?: number;
cursor?: string | null;
sortBy?: AuditSortBy;
sortDirection?: "asc" | "desc";
filters?: Partial<Record<AuditSortBy, string>>;
};
export type AuditAdminListResponse = {
items: AuditAdminItem[];
total: number;
page: number;
page_size: number;
pages: number;
cursor?: string | null;
next_cursor?: string | null;
};
export type AuditAdminDeltaResponse = AuditAdminListResponse & {
deleted: DeltaDeletedItem[];
watermark?: string | null;
has_more: boolean;
full: boolean;
};
export type EvidenceBundleExportRequest = {
scope: "tenant" | "system" | "all";
tenant_id?: string | null;
record_ids?: string[];
max_records?: number;
sign?: boolean;
};
export type EvidenceBundleResponse = {
id: string;
scope: "tenant" | "system" | "all";
tenant_id?: string | null;
status: "pending" | "ready" | "failed";
bundle_sha256?: string | null;
record_count: number;
reference_count: number;
generated_at?: string | null;
download_url?: string | null;
};
export type EvidenceBundleDownloadResponse = {
bundle: Record<string, unknown>;
};
function auditQuery(options: AuditQueryOptions & { since?: string | null } = {}): string {
const params = new URLSearchParams();
if (options.tenantId) params.set("tenant_id", options.tenantId);
if (options.allTenants) params.set("all_tenants", "true");
if (options.scope) params.set("scope", options.scope);
if (options.limit) params.set("limit", String(options.limit));
if (options.offset) params.set("offset", String(options.offset));
if (options.page) params.set("page", String(options.page));
if (options.pageSize) params.set("page_size", String(options.pageSize));
if (options.cursor) params.set("cursor", options.cursor);
if (options.sortBy) params.set("sort_by", options.sortBy);
if (options.sortDirection) params.set("sort_direction", options.sortDirection);
if (options.since) params.set("since", options.since);
for (const [column, value] of Object.entries(options.filters ?? {})) {
if (value?.trim()) params.set(`filter_${column}`, value);
}
const suffix = params.toString();
return suffix ? `?${suffix}` : "";
}
export function fetchAdminAudit(settings: ApiSettings, options: AuditQueryOptions = {}): Promise<AuditAdminListResponse> {
return apiFetch(settings, `/api/v1/admin/audit${auditQuery(options)}`);
}
export function fetchAdminAuditDelta(settings: ApiSettings, options: AuditQueryOptions & { since?: string | null } = {}): Promise<AuditAdminDeltaResponse> {
return apiFetch(settings, `/api/v1/admin/audit/delta${auditQuery(options)}`);
}
export function exportAuditEvidenceBundle(
settings: ApiSettings,
payload: EvidenceBundleExportRequest
): Promise<EvidenceBundleResponse> {
return apiFetch(settings, "/api/v1/admin/audit/evidence-bundles", {
method: "POST",
body: JSON.stringify(payload)
});
}
export function downloadAuditEvidenceBundle(
settings: ApiSettings,
bundleId: string
): Promise<EvidenceBundleDownloadResponse> {
return apiFetch(settings, `/api/v1/admin/audit/evidence-bundles/${bundleId}/download`);
}