import type { H3Event } from "h3"; import { getRequestHeader } from "h3"; /** 与 Nitro `runtime/utils` 一致,避免依赖 `nitropack/.../utils` 的 TS 子路径解析 */ function hasReqHeader(event: H3Event, name: string, includes: string): boolean { const value = getRequestHeader(event, name); return Boolean(value && typeof value === "string" && value.toLowerCase().includes(includes)); } export function isJsonRequest(event: H3Event): boolean { if (hasReqHeader(event, "accept", "text/html")) { return false; } return ( hasReqHeader(event, "accept", "application/json") || hasReqHeader(event, "user-agent", "curl/") || hasReqHeader(event, "user-agent", "httpie/") || hasReqHeader(event, "sec-fetch-mode", "cors") || event.path.startsWith("/api/") || event.path.endsWith(".json") ); } export function normalizeError(error: any, isDev?: boolean) { const cwd = typeof process.cwd === "function" ? process.cwd() : "/"; const stack = !isDev && !import.meta.prerender && (error.unhandled || error.fatal) ? [] : (error.stack || "") .split("\n") .splice(1) .filter((line: string) => line.includes("at ")) .map((line: string) => { const text = line .replace(cwd + "/", "./") .replace("webpack:/", "") .replace("file://", "") .trim(); return { text, internal: (line.includes("node_modules") && !line.includes(".cache")) || line.includes("internal") || line.includes("new Promise"), }; }); const statusCode = error.statusCode || 500; const statusMessage = error.statusMessage ?? (statusCode === 404 ? "Not Found" : ""); const message = !isDev && error.unhandled ? "internal server error" : error.message || error.toString(); return { stack, statusCode, statusMessage, message, }; }