fix: Vercel serverless function crash and await async completions routes

- Make generateDeviceFingerprint resilient to os.cpus() and os.hostname() returning empty or throwing in lambda sandboxes.
- Await async handleChatCompletion and handleAnthropicMessages calls in route handlers to prevent unhandled promise rejections.
- Catch runtime exceptions from completions and return clean HTTP 500 JSON error responses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-24 20:40:09 +07:00
co-authored by Claude Opus 4.8
parent 2171a01974
commit d1d6f607b0
3 changed files with 75 additions and 110 deletions
+20 -5
View File
@@ -34,11 +34,26 @@ const EXPIRY_BUFFER_MS = 300_000; // 5 minutes
* Uses Web Crypto API (available in Bun, Workers, and Node.js 20+).
*/
async function generateDeviceFingerprint(): Promise<string> {
const hostname = os.hostname();
const platform = process.platform;
const arch = process.arch;
const cpus = os.cpus();
const cpuModel = cpus.length > 0 ? (cpus[0]?.model ?? "unknown") : "unknown";
let hostname = "unknown";
try {
hostname = os.hostname() ?? "unknown";
} catch {
// OS module hostname not available in this sandbox
}
const platform = process.platform ?? "unknown";
const arch = process.arch ?? "unknown";
let cpuModel = "unknown";
try {
const cpus = os.cpus();
if (cpus && cpus.length > 0) {
cpuModel = cpus[0]?.model ?? "unknown";
}
} catch {
// OS module cpus not available in this sandbox
}
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
const raw = `${hostname}|${platform}|${arch}|${cpuModel}|${username}`;
+25 -9
View File
@@ -9,7 +9,6 @@ import {
createErrorResponse,
createCorsPreflightResponse,
getCorsHeaders,
classifyFetchError,
} from "./relay-utils";
import { checkBodySize } from "../middleware/body-limiter";
@@ -615,11 +614,18 @@ export async function handleRequest(
try {
const body = await req.json();
const sessionId = crypto.randomUUID();
return handleChatCompletion(body, proxyPool!, sessionPool!, sessionId);
} catch {
return await handleChatCompletion(body, proxyPool!, sessionPool!, sessionId);
} catch (err) {
const isJsonError = err instanceof Error && (err.name === "SyntaxError" || err.message.includes("JSON"));
if (isJsonError) {
return new Response(
JSON.stringify({ error: { message: "Invalid JSON body", type: "invalid_request_error" } }),
{ status: 400, headers: { "Content-Type": "application/json", ...getCorsHeaders() } },
);
}
return new Response(
JSON.stringify({ error: { message: "Invalid JSON body", type: "invalid_request_error" } }),
{ status: 400, headers: { "Content-Type": "application/json", ...getCorsHeaders() } },
JSON.stringify({ error: { message: err instanceof Error ? err.message : "Internal Server Error", type: "server_error" } }),
{ status: 500, headers: { "Content-Type": "application/json", ...getCorsHeaders() } },
);
}
}
@@ -634,14 +640,24 @@ export async function handleRequest(
const body = await req.json();
const sessionId = crypto.randomUUID();
const anthropicVersion = req.headers.get("anthropic-version") ?? undefined;
return handleAnthropicMessages(body, proxyPool!, sessionPool!, sessionId, undefined, anthropicVersion);
} catch {
return await handleAnthropicMessages(body, proxyPool!, sessionPool!, sessionId, undefined, anthropicVersion);
} catch (err) {
const isJsonError = err instanceof Error && (err.name === "SyntaxError" || err.message.includes("JSON"));
if (isJsonError) {
return new Response(
JSON.stringify({
type: "error",
error: { message: "Invalid JSON body", type: "invalid_request_error" },
}),
{ status: 400, headers: { "Content-Type": "application/json", ...getCorsHeaders() } },
);
}
return new Response(
JSON.stringify({
type: "error",
error: { message: "Invalid JSON body", type: "invalid_request_error" },
error: { message: err instanceof Error ? err.message : "Internal Server Error", type: "server_error" },
}),
{ status: 400, headers: { "Content-Type": "application/json", ...getCorsHeaders() } },
{ status: 500, headers: { "Content-Type": "application/json", ...getCorsHeaders() } },
);
}
}