mirror of
https://github.com/khairul169/code-share.git
synced 2026-10-24 11:53:58 +07:00
feat: add sandbox
This commit is contained in:
@@ -2,11 +2,13 @@ import { Router } from "express";
|
||||
import preview from "./preview";
|
||||
import trpc from "./trpc/handler";
|
||||
import { thumbnail } from "./thumbnail";
|
||||
import sandbox from "./sandbox";
|
||||
|
||||
const api = Router();
|
||||
|
||||
api.use("/trpc", trpc);
|
||||
api.use("/preview", preview);
|
||||
api.use("/sandbox", sandbox);
|
||||
|
||||
api.get("/thumbnail/:slug", thumbnail);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ const get = async (req: Request, res: Response) => {
|
||||
}
|
||||
|
||||
if (["css"].includes(ext) && settings.css?.preprocessor === "postcss") {
|
||||
content = await postcss(fileData, settings.css);
|
||||
content = await postcss(projectData, fileData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ import tailwindcss from "tailwindcss";
|
||||
import cssnano from "cssnano";
|
||||
import { FileSchema } from "~/server/db/schema/file";
|
||||
import { unpackProject } from "~/server/lib/unpack-project";
|
||||
import { ProjectSettingsSchema } from "~/server/db/schema/project";
|
||||
import { ProjectSchema } from "~/server/db/schema/project";
|
||||
|
||||
export const postcss = async (
|
||||
fileData: FileSchema,
|
||||
cfg?: ProjectSettingsSchema["css"]
|
||||
) => {
|
||||
export const postcss = async (project: ProjectSchema, fileData: FileSchema) => {
|
||||
const content = fileData.content || "";
|
||||
const cfg = project.settings?.css;
|
||||
|
||||
try {
|
||||
const projectDir = await unpackProject({ ext: "ts,tsx,js,jsx,html" });
|
||||
const projectDir = await unpackProject(project, {
|
||||
ext: "ts,tsx,js,jsx,html",
|
||||
});
|
||||
const plugins: any[] = [];
|
||||
|
||||
if (cfg?.tailwindcss) {
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
import { Router, type Request } from "express";
|
||||
import sandbox from "../lib/sandbox";
|
||||
import db from "~/server/db";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { project } from "~/server/db/schema/project";
|
||||
import { unpackProject } from "../lib/unpack-project";
|
||||
import { APIError } from "~/lib/api";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/:slug/start", async (req, res) => {
|
||||
const { slug } = req.params as any;
|
||||
const data = await getProjectBySlug(slug);
|
||||
if (!data) {
|
||||
return res.status(404).send("Project not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
const path = await unpackProject(data);
|
||||
const result = await sandbox.start(data.slug, path + "/api");
|
||||
|
||||
if (!result.ok) {
|
||||
const body = await result.text();
|
||||
throw new APIError(body, result.status);
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
const error = err as any;
|
||||
res
|
||||
.status(typeof error?.code === "number" ? error.code : 500)
|
||||
.send(error?.message || "An error occured!");
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/:slug/stop", async (req, res) => {
|
||||
const { slug } = req.params as any;
|
||||
const data = await getProjectBySlug(slug);
|
||||
if (!data) {
|
||||
return res.status(404).send("Project not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
await sandbox.stop(data.slug);
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
res.status(500).send("An error occured!");
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/:slug/restart", async (req, res) => {
|
||||
const { slug } = req.params as any;
|
||||
const data = await getProjectBySlug(slug);
|
||||
if (!data) {
|
||||
return res.status(404).send("Project not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
await unpackProject(data);
|
||||
const result = await sandbox.restart(data.slug);
|
||||
|
||||
if (!result.ok) {
|
||||
const body = await result.text();
|
||||
throw new APIError(body, result.status);
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (err) {
|
||||
const error = err as any;
|
||||
res
|
||||
.status(typeof error?.code === "number" ? error.code : 500)
|
||||
.send(error?.message || "An error occured!");
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:slug/stats", async (req, res) => {
|
||||
const { slug } = req.params as any;
|
||||
const data = await getProjectBySlug(slug);
|
||||
if (!data) {
|
||||
return res.status(404).send("Project not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await sandbox.getStats(data.slug);
|
||||
res.json({ success: true, result });
|
||||
} catch (err) {
|
||||
const error = err as any;
|
||||
res
|
||||
.status(typeof error.code === "number" ? error.code : 500)
|
||||
.send(error.message || "An error occured!");
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:slug/logs", async (req, res) => {
|
||||
const { slug } = req.params as any;
|
||||
const data = await getProjectBySlug(slug);
|
||||
if (!data) {
|
||||
return res.status(404).send("Project not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
const { body, headers } = await sandbox.getLogs(data.slug);
|
||||
if (!body) {
|
||||
throw new Error("No body response.");
|
||||
}
|
||||
|
||||
headers.forEach((value, key) => res.setHeader(key, value));
|
||||
body.pipe(res);
|
||||
} catch (err) {
|
||||
res.status(500).send("An error occured!");
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:slug/proxy*", async (req, res) => {
|
||||
const params = req.params as any;
|
||||
const { slug } = params;
|
||||
const pathname = params?.[0];
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
Object.entries(req.query || {}).forEach(([key, value]) => {
|
||||
searchParams.set(key, value as string);
|
||||
});
|
||||
|
||||
const data = await getProjectBySlug(slug);
|
||||
if (!data) {
|
||||
return res.status(404).send("Project not found!");
|
||||
}
|
||||
|
||||
try {
|
||||
const { body, headers, status } = await sandbox.proxy(data.slug, {
|
||||
pathname: pathname + "?" + searchParams.toString(),
|
||||
headers: getHeadersFromReq(req),
|
||||
});
|
||||
|
||||
if (!body) {
|
||||
throw new Error("No body response.");
|
||||
}
|
||||
|
||||
headers.forEach((value, key) => res.setHeader(key, value));
|
||||
res.status(status);
|
||||
body.pipe(res);
|
||||
} catch (err) {
|
||||
const error = err as any;
|
||||
res
|
||||
.status(typeof error?.code === "number" ? error.code : 500)
|
||||
.send(error?.message || "An error occured!");
|
||||
}
|
||||
});
|
||||
|
||||
function getHeadersFromReq(req: Request) {
|
||||
const headers = new Headers();
|
||||
|
||||
for (const [key, value] of Object.entries(req.headers)) {
|
||||
if (typeof value === "string") {
|
||||
headers.set(key, value);
|
||||
} else if (Array.isArray(value)) {
|
||||
value.forEach((val) => headers.append(key, val));
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
async function getProjectBySlug(slug: string) {
|
||||
return db.query.project.findFirst({
|
||||
where: and(eq(project.slug, slug), isNull(project.deletedAt)),
|
||||
});
|
||||
}
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user