Files
breakpilot-compliance/admin-compliance/lib/sdk/api-client-operations.ts
Sharang Parnerkar e07e1de6c9 refactor(admin): split api-client.ts (885 LOC) and endpoints.ts (1262 LOC) into focused modules
api-client.ts is now a thin delegating class (263 LOC) backed by:
  - api-client-types.ts (84) — shared types, config, FetchContext
  - api-client-state.ts (120) — state CRUD + export
  - api-client-projects.ts (160) — project management
  - api-client-wiki.ts (116) — wiki knowledge base
  - api-client-operations.ts (299) — checkpoints, flow, modules, UCCA, import, screening

endpoints.ts is now a barrel (25 LOC) aggregating the 4 existing domain files
(endpoints-python-core, endpoints-python-gdpr, endpoints-python-ops, endpoints-go).

All files stay under the 500-line hard cap. Build verified with `npx next build`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:17:38 +02:00

300 lines
7.4 KiB
TypeScript

/**
* SDK API Client — Operational methods.
* (checkpoints, flow, modules, UCCA, document import, screening, health)
*/
import {
APIResponse,
CheckpointValidationResult,
FetchContext,
CheckpointStatus,
} from './api-client-types'
// ---------------------------------------------------------------------------
// Checkpoint Validation
// ---------------------------------------------------------------------------
/**
* Validate a specific checkpoint
*/
export async function validateCheckpoint(
ctx: FetchContext,
checkpointId: string,
data?: unknown
): Promise<CheckpointValidationResult> {
const response = await ctx.fetchWithRetry<APIResponse<CheckpointValidationResult>>(
`${ctx.baseUrl}/checkpoints/validate`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenantId: ctx.tenantId,
checkpointId,
data,
}),
}
)
if (!response.success || !response.data) {
throw ctx.createError(response.error || 'Checkpoint validation failed', 500, true)
}
return response.data
}
/**
* Get all checkpoint statuses
*/
export async function getCheckpoints(
ctx: FetchContext
): Promise<Record<string, CheckpointStatus>> {
const response = await ctx.fetchWithRetry<APIResponse<Record<string, CheckpointStatus>>>(
`${ctx.baseUrl}/checkpoints?tenantId=${encodeURIComponent(ctx.tenantId)}`,
{
method: 'GET',
headers: { 'Content-Type': 'application/json' },
}
)
return response.data || {}
}
// ---------------------------------------------------------------------------
// Flow Navigation
// ---------------------------------------------------------------------------
/**
* Get current flow state
*/
export async function getFlowState(ctx: FetchContext): Promise<{
currentStep: string
currentPhase: 1 | 2
completedSteps: string[]
suggestions: Array<{ stepId: string; reason: string }>
}> {
const response = await ctx.fetchWithRetry<APIResponse<{
currentStep: string
currentPhase: 1 | 2
completedSteps: string[]
suggestions: Array<{ stepId: string; reason: string }>
}>>(
`${ctx.baseUrl}/flow?tenantId=${encodeURIComponent(ctx.tenantId)}`,
{
method: 'GET',
headers: { 'Content-Type': 'application/json' },
}
)
if (!response.data) {
throw ctx.createError('Failed to get flow state', 500, true)
}
return response.data
}
/**
* Navigate to next/previous step
*/
export async function navigateFlow(
ctx: FetchContext,
direction: 'next' | 'previous'
): Promise<{ stepId: string; phase: 1 | 2 }> {
const response = await ctx.fetchWithRetry<APIResponse<{
stepId: string
phase: 1 | 2
}>>(
`${ctx.baseUrl}/flow`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
tenantId: ctx.tenantId,
direction,
}),
}
)
if (!response.data) {
throw ctx.createError('Failed to navigate flow', 500, true)
}
return response.data
}
// ---------------------------------------------------------------------------
// Modules
// ---------------------------------------------------------------------------
/**
* Get available compliance modules from backend
*/
export async function getModules(
ctx: FetchContext,
filters?: {
serviceType?: string
criticality?: string
processesPii?: boolean
aiComponents?: boolean
}
): Promise<{ modules: unknown[]; total: number }> {
const params = new URLSearchParams()
if (filters?.serviceType) params.set('service_type', filters.serviceType)
if (filters?.criticality) params.set('criticality', filters.criticality)
if (filters?.processesPii !== undefined) params.set('processes_pii', String(filters.processesPii))
if (filters?.aiComponents !== undefined) params.set('ai_components', String(filters.aiComponents))
const queryString = params.toString()
const url = `${ctx.baseUrl}/modules${queryString ? `?${queryString}` : ''}`
const response = await ctx.fetchWithRetry<{ modules: unknown[]; total: number }>(
url,
{
method: 'GET',
headers: { 'Content-Type': 'application/json' },
}
)
return response
}
// ---------------------------------------------------------------------------
// UCCA (Use Case Compliance Assessment)
// ---------------------------------------------------------------------------
/**
* Assess a use case
*/
export async function assessUseCase(
ctx: FetchContext,
intake: unknown
): Promise<unknown> {
const response = await ctx.fetchWithRetry<APIResponse<unknown>>(
`${ctx.baseUrl}/ucca/assess`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Tenant-ID': ctx.tenantId,
},
body: JSON.stringify(intake),
}
)
return response
}
/**
* Get all assessments
*/
export async function getAssessments(ctx: FetchContext): Promise<unknown[]> {
const response = await ctx.fetchWithRetry<APIResponse<unknown[]>>(
`${ctx.baseUrl}/ucca/assessments?tenantId=${encodeURIComponent(ctx.tenantId)}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Tenant-ID': ctx.tenantId,
},
}
)
return response.data || []
}
/**
* Get a single assessment
*/
export async function getAssessment(
ctx: FetchContext,
id: string
): Promise<unknown> {
const response = await ctx.fetchWithRetry<APIResponse<unknown>>(
`${ctx.baseUrl}/ucca/assessments/${id}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Tenant-ID': ctx.tenantId,
},
}
)
return response.data
}
/**
* Delete an assessment
*/
export async function deleteAssessment(
ctx: FetchContext,
id: string
): Promise<void> {
await ctx.fetchWithRetry<APIResponse<void>>(
`${ctx.baseUrl}/ucca/assessments/${id}`,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-Tenant-ID': ctx.tenantId,
},
}
)
}
// ---------------------------------------------------------------------------
// Document Import & Screening
// ---------------------------------------------------------------------------
/**
* Analyze an uploaded document
*/
export async function analyzeDocument(
ctx: FetchContext,
formData: FormData
): Promise<unknown> {
const response = await ctx.fetchWithRetry<APIResponse<unknown>>(
`${ctx.baseUrl}/import/analyze`,
{
method: 'POST',
headers: { 'X-Tenant-ID': ctx.tenantId },
body: formData,
}
)
return response.data
}
/**
* Scan a dependency file (package-lock.json, requirements.txt, etc.)
*/
export async function scanDependencies(
ctx: FetchContext,
formData: FormData
): Promise<unknown> {
const response = await ctx.fetchWithRetry<APIResponse<unknown>>(
`${ctx.baseUrl}/screening/scan`,
{
method: 'POST',
headers: { 'X-Tenant-ID': ctx.tenantId },
body: formData,
}
)
return response.data
}
// ---------------------------------------------------------------------------
// Health
// ---------------------------------------------------------------------------
/**
* Health check
*/
export async function healthCheck(ctx: FetchContext): Promise<boolean> {
try {
const response = await ctx.fetchWithTimeout(
`${ctx.baseUrl}/health`,
{ method: 'GET' },
`health-${Date.now()}`
)
return response.ok
} catch {
return false
}
}