import { NextResponse } from "next/server"; import { testRouteDenied } from "../_guard"; export const dynamic = "force-dynamic"; // E2E test harness only. Counts uncaughtException + unhandledRejection // events seen by the dev-server's Node process so a spec can assert that // "Controller is already closed" no longer leaks out of the streaming job // pipeline when the consumer disconnects. // // The process-level handler is installed once on first module load. It's // gated by the test-fixture TRANSCRIPTS_DIR path so production-shaped // installs never see it. type CountState = { uncaught: number; unhandled: number; messages: string[]; }; declare global { // eslint-disable-next-line no-var var __yttUncaughtCount__: CountState | undefined; } function isTestEnv(): boolean { const dir = process.env.TRANSCRIPTS_DIR ?? ""; return dir.endsWith("test-transcripts"); } function getState(): CountState { if (!globalThis.__yttUncaughtCount__) { globalThis.__yttUncaughtCount__ = { uncaught: 0, unhandled: 0, messages: [], }; if (isTestEnv()) { process.on("uncaughtException", (err) => { const s = globalThis.__yttUncaughtCount__!; s.uncaught++; s.messages.push(`uncaught: ${(err as Error)?.message ?? String(err)}`); if (s.messages.length > 50) s.messages.shift(); }); process.on("unhandledRejection", (reason) => { const s = globalThis.__yttUncaughtCount__!; s.unhandled++; s.messages.push( `unhandled: ${(reason as Error)?.message ?? String(reason)}`, ); if (s.messages.length > 50) s.messages.shift(); }); } } return globalThis.__yttUncaughtCount__; } export async function GET() { const denied = testRouteDenied(); if (denied) return denied; const state = getState(); return NextResponse.json({ uncaught: state.uncaught, unhandled: state.unhandled, messages: state.messages.slice(), }); } export async function DELETE() { const denied = testRouteDenied(); if (denied) return denied; const state = getState(); state.uncaught = 0; state.unhandled = 0; state.messages.length = 0; return NextResponse.json({ ok: true }); }