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>
This commit is contained in:
120
admin-compliance/lib/sdk/api-client-state.ts
Normal file
120
admin-compliance/lib/sdk/api-client-state.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* SDK API Client — State management methods.
|
||||
* (getState, saveState, deleteState, exportState)
|
||||
*/
|
||||
|
||||
import {
|
||||
APIResponse,
|
||||
APIError,
|
||||
StateResponse,
|
||||
FetchContext,
|
||||
SDKState,
|
||||
} from './api-client-types'
|
||||
|
||||
/**
|
||||
* Load SDK state for the current tenant
|
||||
*/
|
||||
export async function getState(ctx: FetchContext): Promise<StateResponse | null> {
|
||||
try {
|
||||
const params = new URLSearchParams({ tenantId: ctx.tenantId })
|
||||
if (ctx.projectId) params.set('projectId', ctx.projectId)
|
||||
const response = await ctx.fetchWithRetry<APIResponse<StateResponse>>(
|
||||
`${ctx.baseUrl}/state?${params.toString()}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}
|
||||
)
|
||||
|
||||
if (response.success && response.data) {
|
||||
return response.data
|
||||
}
|
||||
|
||||
return null
|
||||
} catch (error) {
|
||||
const apiError = error as APIError
|
||||
// 404 means no state exists yet - that's okay
|
||||
if (apiError.status === 404) {
|
||||
return null
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save SDK state for the current tenant.
|
||||
* Supports optimistic locking via version parameter.
|
||||
*/
|
||||
export async function saveState(
|
||||
ctx: FetchContext,
|
||||
state: SDKState,
|
||||
version?: number
|
||||
): Promise<StateResponse> {
|
||||
const response = await ctx.fetchWithRetry<APIResponse<StateResponse>>(
|
||||
`${ctx.baseUrl}/state`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(version !== undefined && { 'If-Match': String(version) }),
|
||||
},
|
||||
body: JSON.stringify({
|
||||
tenantId: ctx.tenantId,
|
||||
projectId: ctx.projectId,
|
||||
state,
|
||||
version,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.success) {
|
||||
throw ctx.createError(response.error || 'Failed to save state', 500, true)
|
||||
}
|
||||
|
||||
return response.data!
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete SDK state for the current tenant
|
||||
*/
|
||||
export async function deleteState(ctx: FetchContext): Promise<void> {
|
||||
const params = new URLSearchParams({ tenantId: ctx.tenantId })
|
||||
if (ctx.projectId) params.set('projectId', ctx.projectId)
|
||||
await ctx.fetchWithRetry<APIResponse<void>>(
|
||||
`${ctx.baseUrl}/state?${params.toString()}`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Export SDK state in various formats
|
||||
*/
|
||||
export async function exportState(
|
||||
ctx: FetchContext,
|
||||
format: 'json' | 'pdf' | 'zip'
|
||||
): Promise<Blob> {
|
||||
const response = await ctx.fetchWithTimeout(
|
||||
`${ctx.baseUrl}/export?tenantId=${encodeURIComponent(ctx.tenantId)}&format=${format}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept':
|
||||
format === 'json'
|
||||
? 'application/json'
|
||||
: format === 'pdf'
|
||||
? 'application/pdf'
|
||||
: 'application/zip',
|
||||
},
|
||||
},
|
||||
`export-${Date.now()}`
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
throw ctx.createError(`Export failed: ${response.statusText}`, response.status, true)
|
||||
}
|
||||
|
||||
return response.blob()
|
||||
}
|
||||
Reference in New Issue
Block a user