morphbox
Version:
Docker-based AI sandbox for development with Claude integration
198 lines (195 loc) • 5.89 kB
JavaScript
import { e as error, j as json } from './index-3BbzJtgI.js';
import { promises } from 'fs';
import path from 'path';
import { W as WORKSPACE_DIR } from './workspace-CcQOwpY7.js';
import 'child_process';
import 'util';
function validatePath(requestPath) {
const normalized = path.normalize(path.join(WORKSPACE_DIR, requestPath));
if (!normalized.startsWith(WORKSPACE_DIR)) {
throw error(403, "Access denied: Path outside workspace directory");
}
return normalized;
}
const GET = async ({ url }) => {
try {
const requestPath = url.searchParams.get("path") || "/";
const fullPath = validatePath(requestPath);
const stats = await promises.stat(fullPath);
if (!stats.isDirectory()) {
throw error(400, "Path is not a directory");
}
const items = await promises.readdir(fullPath, { withFileTypes: true });
const contents = await Promise.all(
items.map(async (item) => {
const itemPath = path.join(fullPath, item.name);
const itemStats = await promises.stat(itemPath);
return {
name: item.name,
type: item.isDirectory() ? "directory" : "file",
path: path.relative(WORKSPACE_DIR, itemPath),
size: itemStats.size,
modified: itemStats.mtime.toISOString(),
created: itemStats.birthtime.toISOString()
};
})
);
return json({
path: path.relative(WORKSPACE_DIR, fullPath),
contents: contents.sort((a, b) => {
if (a.type !== b.type) {
return a.type === "directory" ? -1 : 1;
}
return a.name.localeCompare(b.name);
})
});
} catch (err) {
if (err instanceof Response) throw err;
if (err.code === "ENOENT") {
throw error(404, "Directory not found");
}
console.error("Error listing directory:", err);
throw error(500, "Failed to list directory");
}
};
const POST = async ({ request, url }) => {
try {
const operation = url.searchParams.get("operation");
const body = await request.json();
switch (operation) {
case "read":
return await handleRead(body);
case "write":
return await handleWrite(body);
case "create":
return await handleCreate(body);
case "rename":
return await handleRename(body);
default:
throw error(400, "Invalid operation");
}
} catch (err) {
if (err instanceof Response) throw err;
console.error("Error in file operation:", err);
throw error(500, "File operation failed");
}
};
const DELETE = async ({ request }) => {
try {
const { path: filePath } = await request.json();
if (!filePath) {
throw error(400, "Path is required");
}
const fullPath = validatePath(filePath);
const stats = await promises.stat(fullPath);
if (stats.isDirectory()) {
await promises.rmdir(fullPath, { recursive: true });
} else {
await promises.unlink(fullPath);
}
return json({
success: true,
message: "File deleted successfully",
path: filePath
});
} catch (err) {
if (err instanceof Response) throw err;
if (err.code === "ENOENT") {
throw error(404, "File not found");
}
console.error("Error deleting file:", err);
throw error(500, "Failed to delete file");
}
};
async function handleRead(body) {
const { path: filePath } = body;
if (!filePath) {
throw error(400, "Path is required");
}
const fullPath = validatePath(filePath);
const stats = await promises.stat(fullPath);
if (stats.isDirectory()) {
throw error(400, "Path is a directory, not a file");
}
const content = await promises.readFile(fullPath, "utf-8");
return json({
path: filePath,
content,
size: stats.size,
modified: stats.mtime.toISOString()
});
}
async function handleWrite(body) {
const { path: filePath, content } = body;
if (!filePath) {
throw error(400, "Path is required");
}
if (content === void 0) {
throw error(400, "Content is required");
}
const fullPath = validatePath(filePath);
const dir = path.dirname(fullPath);
await promises.mkdir(dir, { recursive: true });
await promises.writeFile(fullPath, content, "utf-8");
const stats = await promises.stat(fullPath);
return json({
success: true,
path: filePath,
size: stats.size,
modified: stats.mtime.toISOString()
});
}
async function handleCreate(body) {
const { path: filePath, type = "file", content = "" } = body;
if (!filePath) {
throw error(400, "Path is required");
}
const fullPath = validatePath(filePath);
try {
await promises.access(fullPath);
throw error(409, `${type === "directory" ? "Directory" : "File"} already exists`);
} catch (err) {
if (err.code !== "ENOENT") {
throw err;
}
}
if (type === "directory") {
await promises.mkdir(fullPath, { recursive: true });
} else {
const dir = path.dirname(fullPath);
await promises.mkdir(dir, { recursive: true });
await promises.writeFile(fullPath, content, "utf-8");
}
return json({
success: true,
path: filePath,
type
});
}
async function handleRename(body) {
const { oldPath, newPath } = body;
if (!oldPath || !newPath) {
throw error(400, "Both oldPath and newPath are required");
}
const fullOldPath = validatePath(oldPath);
const fullNewPath = validatePath(newPath);
await promises.access(fullOldPath);
try {
await promises.access(fullNewPath);
throw error(409, "Destination already exists");
} catch (err) {
if (err.code !== "ENOENT") {
throw err;
}
}
const destDir = path.dirname(fullNewPath);
await promises.mkdir(destDir, { recursive: true });
await promises.rename(fullOldPath, fullNewPath);
return json({
success: true,
oldPath,
newPath
});
}
export { DELETE, GET, POST };
//# sourceMappingURL=_server.ts-T3xWBEB9.js.map