项目文件夹

文件
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

62 行
1.8 KiB
TypeScript

import { Readable } from "node:stream";
import { NextResponse } from "next/server";
import { checkRateLimit } from "@/lib/rate-limit";
import { isAiPlaygroundEnabled } from "@/lib/feature-flags";
import { exportWorkspaceArchive } from "../blaxel-sandbox";
export const maxDuration = 120;
export async function POST(request: Request) {
if (!isAiPlaygroundEnabled) {
return NextResponse.json({ error: "Not found." }, { status: 404 });
}
let cleanup: (() => Promise<void>) | undefined;
const runCleanup = () => {
const current = cleanup;
cleanup = undefined;
return current?.().catch(() => {});
};
try {
const rateLimitResponse = await checkRateLimit(request);
if (rateLimitResponse) return rateLimitResponse;
const body = (await request.json().catch(() => null)) as {
sessionId?: unknown;
} | null;
const sessionId = body?.sessionId;
if (typeof sessionId !== "string" || sessionId.length === 0) {
return NextResponse.json(
{ error: "Missing sessionId." },
{ status: 400 },
);
}
const archive = await exportWorkspaceArchive(sessionId);
cleanup = archive.cleanup;
const stream = Readable.toWeb(archive.stream) as ReadableStream;
archive.stream.on("close", () => {
void runCleanup();
});
archive.stream.on("error", () => {
void runCleanup();
});
return new Response(stream, {
headers: {
"Content-Type": archive.contentType,
"Content-Disposition": `attachment; filename="${archive.filename}"`,
"Cache-Control": "no-store",
},
});
} catch (error) {
console.error("Failed to download Xulux workspace archive", error);
await runCleanup();
return NextResponse.json(
{ error: "Failed to download workspace." },
{ status: 500 },
);
}
}