Add read-only production runtime audit

This commit is contained in:
2026-08-17 11:17:40 +07:00
parent 057d4ed9dc
commit a1de4715a4
106 changed files with 6869 additions and 1782 deletions
+3
View File
@@ -227,11 +227,13 @@ function toCitations(raw: RagCitation[]): Citation[] {
export async function POST(request: Request) {
let content: string;
let conversationId: string | null = null;
let responseMode: "ai" | "monograph" = "ai";
try {
const body = await request.json();
content = typeof body?.content === "string" ? body.content.trim() : "";
conversationId =
typeof body?.conversationId === "string" ? body.conversationId : null;
responseMode = body?.responseMode === "monograph" ? "monograph" : "ai";
} catch {
return NextResponse.json({ error: "invalid_body" }, { status: 400 });
}
@@ -277,6 +279,7 @@ export async function POST(request: Request) {
subject_scope: "human",
intent: "fact_lookup",
conversation_id: conversationId,
response_mode: responseMode,
}),
cache: "no-store",
// Propagate a browser disconnect/Stop action to the upstream fetch.
+3 -3
View File
@@ -14,9 +14,8 @@ export async function GET(request: Request) {
}
try {
const targetUrl = API_GATEWAY_URL.includes("/v1/rag")
? `${API_GATEWAY_URL.replace(/\/query$/, "/history")}?conversation_id=${encodeURIComponent(conversationId)}`
: `${API_GATEWAY_URL}/v1/rag/history?conversation_id=${encodeURIComponent(conversationId)}`;
const base = API_GATEWAY_URL.replace(/\/v1\/rag(?:\/query)?\/?$/, "");
const targetUrl = `${base}/v1/rag/history?conversation_id=${encodeURIComponent(conversationId)}`;
const upstream = await fetch(targetUrl, {
method: "GET",
@@ -24,6 +23,7 @@ export async function GET(request: Request) {
"X-Client-Version": "1.0.0",
},
cache: "no-store",
signal: AbortSignal.timeout(8_000),
});
if (!upstream.ok) {
+41
View File
@@ -0,0 +1,41 @@
import { NextResponse } from "next/server";
export const runtime = "nodejs";
const API_GATEWAY_URL =
process.env.API_GATEWAY_URL ?? process.env.AI_SERVICE_URL ?? "http://localhost:8000";
function ragBaseUrl() {
return API_GATEWAY_URL.replace(/\/v1\/rag(?:\/query)?\/?$/, "");
}
export async function GET(request: Request) {
const params = new URL(request.url).searchParams;
const drugId = params.get("drug_id")?.trim() ?? "";
const sectionKey = params.get("section_key")?.trim() ?? "";
if (
!/^[a-z0-9_]{1,160}$/i.test(drugId) ||
!/^[a-z0-9_]{1,80}$/i.test(sectionKey)
) {
return NextResponse.json({ error: "invalid_section_request" }, { status: 400 });
}
try {
const upstream = await fetch(
`${ragBaseUrl()}/v1/rag/section-text?drug_id=${encodeURIComponent(
drugId
)}&section_key=${encodeURIComponent(sectionKey)}`,
{
headers: { "X-Client-Version": "1.0.0" },
cache: "no-store",
signal: AbortSignal.timeout(12_000),
}
);
if (!upstream.ok) {
return NextResponse.json({ error: "section_text_unavailable" }, { status: upstream.status });
}
return NextResponse.json(await upstream.json());
} catch {
return NextResponse.json({ error: "section_text_unavailable" }, { status: 502 });
}
}
+34
View File
@@ -0,0 +1,34 @@
import { NextResponse } from "next/server";
export const runtime = "nodejs";
const API_GATEWAY_URL =
process.env.API_GATEWAY_URL ?? process.env.AI_SERVICE_URL ?? "http://localhost:8000";
function ragBaseUrl() {
return API_GATEWAY_URL.replace(/\/v1\/rag(?:\/query)?\/?$/, "");
}
export async function GET(request: Request) {
const drugId = new URL(request.url).searchParams.get("drug_id")?.trim() ?? "";
if (!/^[a-z0-9_]{1,160}$/i.test(drugId)) {
return NextResponse.json({ error: "invalid_drug_id" }, { status: 400 });
}
try {
const upstream = await fetch(
`${ragBaseUrl()}/v1/rag/sections?drug_id=${encodeURIComponent(drugId)}`,
{
headers: { "X-Client-Version": "1.0.0" },
cache: "no-store",
signal: AbortSignal.timeout(8_000),
}
);
if (!upstream.ok) {
return NextResponse.json({ error: "sections_unavailable" }, { status: upstream.status });
}
return NextResponse.json(await upstream.json());
} catch {
return NextResponse.json({ error: "sections_unavailable" }, { status: 502 });
}
}