export default { async fetch(request, env) { const method = request.method; // Allow only POST (upload) and DELETE if (method !== "POST" && method !== "DELETE") { return new Response("Method Not Allowed", { status: 405 }); } const contentType = request.headers.get("content-type") || ""; let site, path, file; // Handle DELETE if (method === "DELETE") { const url = new URL(request.url); site = url.searchParams.get("site"); path = url.searchParams.get("path"); if (!site || !path) { return new Response("Missing site or path", { status: 400 }); } } // Handle POST (upload) if (method === "POST") { if (!contentType.includes("multipart/form-data")) { return new Response("Invalid Content-Type", { status: 400 }); } const form = await request.formData(); site = form.get("site"); path = form.get("path"); file = form.get("file"); if (!site || !path || !file) { return new Response("Missing site, path, or file", { status: 400 }); } } // Validate inputs if (!isValidSite(site) || !isValidPath(path)) { return new Response("Invalid site or path", { status: 400 }); } const key = `site:${site}:${path}`; // DELETE logic if (method === "DELETE") { await env.PAGES_KV.delete(key); return new Response("Deleted", { status: 200 }); } // POST logic (upload / redeploy) const data = await file.arrayBuffer(); await env.PAGES_KV.put(key, data); return new Response("Uploaded", { status: 200 }); }, }; function isValidSite(site) { return /^[a-z0-9-]{1,50}$/.test(site); } function isValidPath(path) { return ( typeof path === "string" && !path.includes("..") && !path.startsWith("/") && path.length <= 200 ); }