mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
- Add auth0.getSession() to unauthenticated observability endpoints (llm-call-debug, llm-export, observability chat) - Remove hardcoded JWT_SECRET fallback; require env var - Sanitize markdown HTML with DOMPurify before innerHTML assignment - Escape user data in Intercom boot snippet via JSON.stringify - Add security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) via next.config.mjs - Move OAuth params from sessionStorage to signed HttpOnly cookie - Add input validation: clamp page/pageSize bounds, allowlist sort fields - Stop leaking error.message to clients in API responses - Remove ~40 console.log/error statements that logged user IDs, org IDs, PKCE params, and OAuth flow details - Delete unused api-client.ts (NEXT_PUBLIC_CF_API_KEY never imported)
232 lines
7.4 KiB
TypeScript
232 lines
7.4 KiB
TypeScript
import { type NextRequest, NextResponse } from "next/server"
|
|
import { auth0 } from "@/lib/auth0"
|
|
import { getTraceData, type TraceData } from "@/app/observability/lib/get-trace-data"
|
|
import { transformToTimelineSections } from "@/app/observability/components/timeline-types"
|
|
import { formatTimelineForLLM } from "@/app/observability/components/format-llm-export"
|
|
|
|
function getFunctionName(
|
|
metadata: Record<string, unknown> | undefined,
|
|
optimizationEvent: TraceData["optimizationEvent"],
|
|
): string | null {
|
|
const metadataFunctionName = metadata?.function_to_optimize as string | undefined
|
|
return metadataFunctionName ?? optimizationEvent?.function_name ?? null
|
|
}
|
|
|
|
function getFilePath(
|
|
optimizationEvent: TraceData["optimizationEvent"],
|
|
metadata: Record<string, unknown> | undefined,
|
|
): string | null {
|
|
const eventFilePath = optimizationEvent?.file_path
|
|
const metadataFilePath = metadata?.file_path as string | undefined
|
|
return eventFilePath ?? metadataFilePath ?? null
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const session = await auth0.getSession()
|
|
if (!session?.user?.sub) {
|
|
return new NextResponse("Unauthorized", { status: 401 })
|
|
}
|
|
|
|
const traceId = request.nextUrl.searchParams.get("trace_id")?.trim()
|
|
|
|
if (!traceId) {
|
|
return new NextResponse("No trace ID provided.", {
|
|
status: 400,
|
|
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
|
})
|
|
}
|
|
|
|
const tracePrefix = traceId.substring(0, 33)
|
|
const traceData = await getTraceData(tracePrefix)
|
|
|
|
if (traceData.rawLlmCalls.length === 0 && traceData.errors.length === 0) {
|
|
return new NextResponse(`No data found for trace: ${traceId}`, {
|
|
status: 404,
|
|
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
|
})
|
|
}
|
|
|
|
const { rawLlmCalls, errors, optimizationFeatures, optimizationEvent } = traceData
|
|
|
|
const optimizationsOrigin =
|
|
(optimizationFeatures?.optimizations_origin as Record<
|
|
string,
|
|
{ source: string; model?: string; call_sequence?: number; parent?: string }
|
|
>) || {}
|
|
|
|
const candidateExplanations =
|
|
(optimizationFeatures?.explanations_post as Record<string, string>) || {}
|
|
|
|
const allCandidates = optimizationFeatures?.optimizations_post
|
|
? Object.entries(optimizationFeatures.optimizations_post as Record<string, string>).map(
|
|
([id, code]) => ({
|
|
id,
|
|
code: typeof code === "string" ? code : "",
|
|
source: optimizationsOrigin[id]?.source || "OPTIMIZE",
|
|
model: optimizationsOrigin[id]?.model,
|
|
callSequence: optimizationsOrigin[id]?.call_sequence,
|
|
explanation: candidateExplanations[id],
|
|
}),
|
|
)
|
|
: []
|
|
|
|
const optimizationCandidates = allCandidates
|
|
.filter(c => c.source === "OPTIMIZE")
|
|
.sort((a, b) => (a.callSequence ?? Infinity) - (b.callSequence ?? Infinity))
|
|
.map((c, index) => ({ ...c, index: index + 1 }))
|
|
|
|
const lineProfilerCandidates = allCandidates
|
|
.filter(c => c.source === "OPTIMIZE_LP")
|
|
.sort((a, b) => (a.callSequence ?? Infinity) - (b.callSequence ?? Infinity))
|
|
.map((c, index) => ({ ...c, index: index + 1 }))
|
|
|
|
const refinementCandidates = allCandidates
|
|
.filter(c => c.source === "REFINE")
|
|
.sort((a, b) => (a.callSequence ?? Infinity) - (b.callSequence ?? Infinity))
|
|
.map((c, index) => ({
|
|
...c,
|
|
index: index + 1,
|
|
parentId: optimizationsOrigin[c.id]?.parent || null,
|
|
}))
|
|
|
|
const adaptiveCandidates = allCandidates
|
|
.filter(c => c.source === "ADAPTIVE")
|
|
.sort((a, b) => (a.callSequence ?? Infinity) - (b.callSequence ?? Infinity))
|
|
.map((c, index) => ({
|
|
...c,
|
|
index: index + 1,
|
|
parentId: optimizationsOrigin[c.id]?.parent || null,
|
|
}))
|
|
|
|
const rankingData = optimizationFeatures?.ranking as {
|
|
ranking?: string[]
|
|
explanation?: string
|
|
} | null
|
|
const bestCandidateId = rankingData?.ranking?.[0] ?? null
|
|
|
|
const pullRequestRaw = optimizationFeatures?.pull_request
|
|
const usedForPr = Boolean(
|
|
pullRequestRaw != null &&
|
|
typeof pullRequestRaw === "object" &&
|
|
!Array.isArray(pullRequestRaw) &&
|
|
Object.keys(pullRequestRaw as Record<string, unknown>).length > 0,
|
|
)
|
|
|
|
const rankMap: Record<string, number> = {}
|
|
if (rankingData?.ranking) {
|
|
rankingData.ranking.forEach((id, index) => {
|
|
rankMap[id] = index + 1
|
|
})
|
|
}
|
|
|
|
const generatedTests = ((optimizationFeatures?.generated_test ?? []) as string[]).map(
|
|
(code: string, index: number) => ({
|
|
code,
|
|
index: index + 1,
|
|
}),
|
|
)
|
|
|
|
const instrumentedTests = (
|
|
(optimizationFeatures?.instrumented_generated_test ?? []) as string[]
|
|
).map((code: string, index: number) => ({
|
|
code,
|
|
index: index + 1,
|
|
}))
|
|
|
|
const instrumentedPerfTests = (
|
|
(optimizationFeatures?.instrumented_perf_test ?? []) as string[]
|
|
).map((code: string, index: number) => ({
|
|
code,
|
|
index: index + 1,
|
|
}))
|
|
|
|
type RawLlmCall = {
|
|
id: string
|
|
trace_id: string | null
|
|
call_type: string | null
|
|
model_name: string | null
|
|
status: string
|
|
latency_ms: number | null
|
|
llm_cost: number | null
|
|
total_tokens: number | null
|
|
created_at: Date
|
|
context: unknown
|
|
}
|
|
|
|
const llmCalls = (rawLlmCalls as RawLlmCall[]).sort((a: RawLlmCall, b: RawLlmCall) => {
|
|
const seqA = (a.context as { call_sequence?: number } | null)?.call_sequence ?? Infinity
|
|
const seqB = (b.context as { call_sequence?: number } | null)?.call_sequence ?? Infinity
|
|
if (seqA !== seqB) return seqA - seqB
|
|
return new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
|
|
})
|
|
|
|
const transformedCalls = llmCalls.map((call: RawLlmCall) => ({
|
|
id: call.id,
|
|
call_type: call.call_type,
|
|
model_name: call.model_name,
|
|
status: call.status,
|
|
latency_ms: call.latency_ms,
|
|
llm_cost: call.llm_cost,
|
|
total_tokens: call.total_tokens,
|
|
created_at: call.created_at,
|
|
context: call.context as { call_sequence?: number } | null,
|
|
}))
|
|
|
|
const { sections, totalDuration } = transformToTimelineSections({
|
|
calls: transformedCalls,
|
|
optimizationCandidates,
|
|
lineProfilerCandidates,
|
|
refinementCandidates,
|
|
adaptiveCandidates,
|
|
generatedTests,
|
|
instrumentedTests,
|
|
instrumentedPerfTests,
|
|
originalCode: optimizationFeatures?.original_code ?? null,
|
|
testFramework: optimizationFeatures?.test_framework ?? null,
|
|
candidateRankMap: rankMap,
|
|
bestCandidateId,
|
|
rankingExplanation: rankingData?.explanation ?? null,
|
|
usedForPr,
|
|
})
|
|
|
|
const metadata = optimizationFeatures?.metadata as Record<string, unknown> | undefined
|
|
const functionName = getFunctionName(metadata, optimizationEvent)
|
|
const filePath = getFilePath(optimizationEvent, metadata)
|
|
const originalCode = optimizationFeatures?.original_code ?? null
|
|
|
|
const transformedErrors = errors.map(
|
|
(error: {
|
|
error_type: string | null
|
|
severity: string | null
|
|
error_message: string | null
|
|
context: unknown
|
|
created_at: Date
|
|
}) => ({
|
|
error_type: error.error_type,
|
|
severity: error.severity,
|
|
error_message: error.error_message,
|
|
context: error.context as {
|
|
test_name?: string
|
|
failure_reason?: string
|
|
test_output?: string
|
|
expected?: string
|
|
actual?: string
|
|
} | null,
|
|
created_at: error.created_at,
|
|
}),
|
|
)
|
|
|
|
const formattedText = formatTimelineForLLM({
|
|
traceId,
|
|
functionName,
|
|
filePath,
|
|
originalCode,
|
|
sections,
|
|
errors: transformedErrors,
|
|
totalDuration,
|
|
})
|
|
|
|
return new NextResponse(formattedText, {
|
|
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
|
})
|
|
}
|