feat(diagnostics): Admin dashboard client library (Phase 3.4)
- querySessions, createSession, getSession, updateSession, cancelSession - getTraces, getLogs, getScreenshots - Full TypeScript types for all diagnostics entities
This commit is contained in:
parent
fc8f8d33dc
commit
a5d68decdb
299
dashboards/admin-web/src/lib/diagnostics-client.ts
Normal file
299
dashboards/admin-web/src/lib/diagnostics-client.ts
Normal file
@ -0,0 +1,299 @@
|
||||
/**
|
||||
* 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>;
|
||||
Loading…
Reference in New Issue
Block a user