feat: implement API handler for edge runtime with method validation and target normalization

This commit is contained in:
MythEclipse
2026-05-07 20:35:18 +07:00
parent a6333750e4
commit 9e2f4d39b1
4 changed files with 60 additions and 4 deletions
-1
View File
@@ -5,7 +5,6 @@ node_modules
out
dist
*.tgz
api
# code coverage
coverage
+50
View File
@@ -0,0 +1,50 @@
import {
buildRelayRequest,
createRelayResponse,
normalizeTargetUrl,
stripRelayHeaders,
isAllowedTarget,
} from "../relay-utils";
export const config = { runtime: "edge" };
const ALLOWED_METHODS = new Set(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]);
export default async function handler(req: Request): Promise<Response> {
if (!ALLOWED_METHODS.has(req.method)) {
return new Response(JSON.stringify({ error: "Method not allowed" }), {
status: 405,
headers: { "content-type": "application/json" },
});
}
const target = req.headers.get("x-relay-target");
const relayPath = req.headers.get("x-relay-path") || "/";
const targetUrl = normalizeTargetUrl(target, relayPath);
if (!targetUrl) {
return new Response(
JSON.stringify({ error: "Missing x-relay-target header" }),
{
status: 400,
headers: { "content-type": "application/json" },
},
);
}
if (!isAllowedTarget(targetUrl)) {
return new Response(
JSON.stringify({ error: "Target domain not allowed" }),
{
status: 403,
headers: { "content-type": "application/json" },
},
);
}
const headers = stripRelayHeaders(new Headers(req.headers));
const fetchOptions = buildRelayRequest(req, headers);
const response = await fetch(targetUrl, fetchOptions);
return createRelayResponse(response);
}
+1 -1
View File
@@ -4,7 +4,7 @@
"type": "module",
"private": true,
"scripts": {
"build": "bun build src/index.ts --target=bun --outdir=api && mkdir -p dist && cp public/index.html dist/index.html",
"build": "mkdir -p dist && cp public/index.html dist/index.html",
"start": "bun run src/index.ts",
"dev": "bun --hot run src/index.ts",
"test": "bun test",
+8 -1
View File
@@ -1,5 +1,12 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"bunVersion": "1",
"installCommand": "bun install"
"installCommand": "bun install",
"outputDirectory": "dist",
"rewrites": [
{
"source": "/api/(.*)",
"destination": "/api/index.ts"
}
]
}