learning_ai_common_plat/dashboards/admin-web/src/lib/diagnostics-client.ts
saravanakumardb1 a5d68decdb feat(diagnostics): Admin dashboard client library (Phase 3.4)
- querySessions, createSession, getSession, updateSession, cancelSession
- getTraces, getLogs, getScreenshots
- Full TypeScript types for all diagnostics entities
2026-03-03 09:35:41 -08:00

300 lines
9.5 KiB
TypeScript

/**
* Diagnostics Client Library
* Admin dashboard client for debug sessions, traces, and logs
*/
import { createApiClient } from '@bytelyst/api-client';
import type { ApiClient } from '@bytelyst/api-client';
// =============================================================================
// Types
// =============================================================================
export interface DebugSession {
id: string;
productId: string;
targetUserId?: string;
targetAnonymousId?: string;
targetDeviceId?: string;
targetSessionId?: string;
status: 'pending' | 'active' | 'paused' | 'completed' | 'cancelled';
collectionLevel: 'standard' | 'debug' | 'trace';
captureLogs: boolean;
captureNetwork: boolean;
captureScreenshots: boolean;
screenshotOnError: boolean;
maxDurationMinutes: number;
createdAt: string;
updatedAt: string;
startedAt?: string;
endedAt?: string;
expiresAt: string;
logCount: number;
traceCount: number;
screenshotCount: number;
createdBy: string;
updatedBy?: string;
userConsent?: {
consentedAt: string;
consentMethod: 'prompt' | 'pre_consent' | 'auto';
};
}
export interface CreateSessionRequest {
targetUserId?: string;
targetAnonymousId?: string;
targetDeviceId?: string;
targetSessionId?: string;
collectionLevel: 'standard' | 'debug' | 'trace';
captureLogs?: boolean;
captureNetwork?: boolean;
captureScreenshots?: boolean;
screenshotOnError?: boolean;
maxDurationMinutes?: number;
}
export interface UpdateSessionRequest {
status?: 'active' | 'paused' | 'completed' | 'cancelled';
collectionLevel?: 'standard' | 'debug' | 'trace';
captureLogs?: boolean;
captureNetwork?: boolean;
captureScreenshots?: boolean;
screenshotOnError?: boolean;
maxDurationMinutes?: number;
}
export interface QuerySessionsOptions {
productId: string;
status?: string;
targetUserId?: string;
targetDeviceId?: string;
startDate?: string;
endDate?: string;
limit?: number;
offset?: number;
}
export interface QuerySessionsResult {
sessions: DebugSession[];
total: number;
limit: number;
offset: number;
}
export interface TraceSpan {
id: string;
sessionId: string;
productId: string;
traceId: string;
parentId?: string;
spanId: string;
name: string;
kind?: 'internal' | 'server' | 'client' | 'producer' | 'consumer';
startTime: string;
endTime?: string;
durationMs?: number;
attributes: Record<string, unknown>;
status: 'ok' | 'error' | 'unset';
statusMessage?: string;
events?: Array<{
name: string;
timestamp: string;
attributes?: Record<string, unknown>;
}>;
}
export interface LogEntry {
id: string;
sessionId: string;
productId: string;
level: 'debug' | 'info' | 'warn' | 'error' | 'fatal';
message: string;
messageHash?: string;
timestamp: string;
receivedAt?: string;
module: string;
file?: string;
line?: number;
function?: string;
threadId?: string;
correlationId?: string;
context: Record<string, unknown>;
redaction?: {
fieldsRedacted: string[];
patternsMatched: string[];
};
}
export interface QueryTracesOptions {
sessionId: string;
productId: string;
startTime?: string;
endTime?: string;
name?: string;
status?: string;
limit?: number;
offset?: number;
}
export interface QueryLogsOptions {
sessionId: string;
productId: string;
levels?: ('debug' | 'info' | 'warn' | 'error' | 'fatal')[];
module?: string;
search?: string;
startTime?: string;
endTime?: string;
limit?: number;
offset?: number;
}
// =============================================================================
// Client Factory
// =============================================================================
export interface DiagnosticsClientConfig {
baseUrl: string;
productId: string;
getAuthToken: () => string | null;
}
export function createDiagnosticsClient(config: DiagnosticsClientConfig) {
const client = createApiClient({
baseUrl: config.baseUrl,
getToken: config.getAuthToken,
}) as ApiClient;
return {
// -------------------------------------------------------------------------
// Sessions
// -------------------------------------------------------------------------
async querySessions(options: QuerySessionsOptions): Promise<QuerySessionsResult> {
const params = new URLSearchParams();
params.set('productId', options.productId);
if (options.status) params.set('status', options.status);
if (options.targetUserId) params.set('targetUserId', options.targetUserId);
if (options.targetDeviceId) params.set('targetDeviceId', options.targetDeviceId);
if (options.startDate) params.set('startDate', options.startDate);
if (options.endDate) params.set('endDate', options.endDate);
if (options.limit) params.set('limit', options.limit.toString());
if (options.offset) params.set('offset', options.offset.toString());
const result = await client.safeFetch<QuerySessionsResult>(`/api/diagnostics/sessions?${params.toString()}`);
if (result.error) throw new Error(result.error);
return result.data!;
},
async createSession(request: CreateSessionRequest): Promise<DebugSession> {
const result = await client.safeFetch<DebugSession>('/api/diagnostics/sessions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request),
});
if (result.error) throw new Error(result.error);
return result.data!;
},
async getSession(sessionId: string): Promise<DebugSession> {
const result = await client.safeFetch<DebugSession>(`/api/diagnostics/sessions/${sessionId}`);
if (result.error) throw new Error(result.error);
return result.data!;
},
async updateSession(sessionId: string, request: UpdateSessionRequest): Promise<DebugSession> {
const result = await client.safeFetch<DebugSession>(`/api/diagnostics/sessions/${sessionId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request),
});
if (result.error) throw new Error(result.error);
return result.data!;
},
async cancelSession(sessionId: string, reason?: string): Promise<void> {
const result = await client.safeFetch<void>(`/api/diagnostics/sessions/${sessionId}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ reason }),
});
if (result.error) throw new Error(result.error);
},
// -------------------------------------------------------------------------
// Traces
// -------------------------------------------------------------------------
async getTraces(options: QueryTracesOptions): Promise<{ traces: TraceSpan[]; total: number }> {
const params = new URLSearchParams();
params.set('productId', options.productId);
if (options.startTime) params.set('startTime', options.startTime);
if (options.endTime) params.set('endTime', options.endTime);
if (options.name) params.set('name', options.name);
if (options.status) params.set('status', options.status);
if (options.limit) params.set('limit', options.limit.toString());
if (options.offset) params.set('offset', options.offset.toString());
const result = await client.safeFetch<{ traces: TraceSpan[]; total: number }>(
`/api/diagnostics/sessions/${options.sessionId}/traces?${params.toString()}`
);
if (result.error) throw new Error(result.error);
return result.data!;
},
// -------------------------------------------------------------------------
// Logs
// -------------------------------------------------------------------------
async getLogs(options: QueryLogsOptions): Promise<{ logs: LogEntry[]; total: number }> {
const params = new URLSearchParams();
params.set('productId', options.productId);
if (options.levels) params.set('levels', options.levels.join(','));
if (options.module) params.set('module', options.module);
if (options.search) params.set('search', options.search);
if (options.startTime) params.set('startTime', options.startTime);
if (options.endTime) params.set('endTime', options.endTime);
if (options.limit) params.set('limit', options.limit.toString());
if (options.offset) params.set('offset', options.offset.toString());
const result = await client.safeFetch<{ logs: LogEntry[]; total: number }>(
`/api/diagnostics/sessions/${options.sessionId}/logs?${params.toString()}`
);
if (result.error) throw new Error(result.error);
return result.data!;
},
// -------------------------------------------------------------------------
// Screenshots
// -------------------------------------------------------------------------
async getScreenshots(sessionId: string, productId: string): Promise<
Array<{
id: string;
blobUrl: string;
capturedAt: string;
trigger: string;
width: number;
height: number;
}>
> {
const params = new URLSearchParams();
params.set('productId', productId);
const result = await client.safeFetch<
Array<{
id: string;
blobUrl: string;
capturedAt: string;
trigger: string;
width: number;
height: number;
}>
>(`/api/diagnostics/sessions/${sessionId}/screenshots?${params.toString()}`);
if (result.error) throw new Error(result.error);
return result.data!;
},
};
}
export type DiagnosticsClient = ReturnType<typeof createDiagnosticsClient>;