feat: Add proxy and validation API routes with undici and an insecure HTTP agent.

This commit is contained in:
2025-12-21 01:46:34 +01:00
parent d47ef9efec
commit f893228ee5
5 changed files with 43 additions and 24 deletions
+20 -17
View File
@@ -5,25 +5,26 @@
"": { "": {
"name": "erettsegi-browser", "name": "erettsegi-browser",
"dependencies": { "dependencies": {
"@heroui/react": "latest", "@heroui/react": "^2.8.7",
"framer-motion": "latest", "framer-motion": "^12.23.26",
"next": "latest", "next": "16.1.0",
"next-themes": "latest", "next-themes": "^0.4.6",
"react": "latest", "react": "19.2.3",
"react-dom": "latest", "react-dom": "19.2.3",
"react-icons": "latest", "react-icons": "^5.5.0",
"undici": "^7.16.0",
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "latest", "@biomejs/biome": "2.3.10",
"@tailwindcss/postcss": "latest", "@tailwindcss/postcss": "^4.1.18",
"@types/node": "latest", "@types/node": "25.0.3",
"@types/react": "latest", "@types/react": "19.2.7",
"@types/react-dom": "latest", "@types/react-dom": "19.2.3",
"postcss": "latest", "postcss": "8.5.6",
"prettier": "latest", "prettier": "^3.7.4",
"prettier-plugin-tailwindcss": "latest", "prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "latest", "tailwindcss": "^4.1.18",
"typescript": "latest", "typescript": "5.9.3",
}, },
}, },
}, },
@@ -636,6 +637,8 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"use-composed-ref": ["use-composed-ref@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w=="], "use-composed-ref": ["use-composed-ref@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w=="],
+2 -1
View File
@@ -18,7 +18,8 @@
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react": "19.2.3", "react": "19.2.3",
"react-dom": "19.2.3", "react-dom": "19.2.3",
"react-icons": "^5.5.0" "react-icons": "^5.5.0",
"undici": "^7.16.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.3.10", "@biomejs/biome": "2.3.10",
+5 -1
View File
@@ -1,5 +1,6 @@
import { type NextRequest, NextResponse } from "next/server"; import { type NextRequest, NextResponse } from "next/server";
import { parseSegments, getExternalUrl, type ResourceSlug } from "@/utils/edu"; import { parseSegments, getExternalUrl, type ResourceSlug } from "@/utils/edu";
import { insecureAgent } from "@/utils/http-agent";
export async function GET( export async function GET(
_req: NextRequest, _req: NextRequest,
@@ -32,7 +33,10 @@ export async function GET(
); );
} }
const externalResponse = await fetch(targetUrl, { method: "GET" }); const externalResponse = await fetch(targetUrl, {
method: "GET",
dispatcher: insecureAgent,
} as RequestInit);
if (!externalResponse.ok) { if (!externalResponse.ok) {
return NextResponse.json( return NextResponse.json(
+9 -5
View File
@@ -1,5 +1,6 @@
import { type NextRequest, NextResponse } from "next/server"; import { type NextRequest, NextResponse } from "next/server";
import { parseSegments, getExternalUrl, type ResourceSlug } from "@/utils/edu"; import { parseSegments, getExternalUrl, type ResourceSlug } from "@/utils/edu";
import { insecureAgent } from "@/utils/http-agent";
export async function GET( export async function GET(
_req: NextRequest, _req: NextRequest,
@@ -10,7 +11,7 @@ export async function GET(
const { subject, year, period, level, resourceType } = parseSegments(slug); const { subject, year, period, level, resourceType } = parseSegments(slug);
if (!subject || !year || !period || !level || !resourceType) { if (!subject || !year || !period || !level || !resourceType) {
return NextResponse.json({ status: 400 }); return NextResponse.json({ status: 400 }, { status: 400 });
} }
const targetUrl = getExternalUrl( const targetUrl = getExternalUrl(
@@ -20,11 +21,14 @@ export async function GET(
level, level,
resourceType as ResourceSlug, resourceType as ResourceSlug,
); );
if (!targetUrl) return NextResponse.json({ status: 404 }); if (!targetUrl) return NextResponse.json({ status: 404 }, { status: 404 });
const res = await fetch(targetUrl, { method: "HEAD" }); const res = await fetch(targetUrl, {
return NextResponse.json({ status: res.status }); method: "HEAD",
dispatcher: insecureAgent,
} as RequestInit);
return NextResponse.json({ status: res.status }, { status: res.status });
} catch { } catch {
return NextResponse.json({ status: 500 }); return NextResponse.json({ status: 500 }, { status: 500 });
} }
} }
+7
View File
@@ -0,0 +1,7 @@
import { Agent } from "undici";
export const insecureAgent = new Agent({
connect: {
rejectUnauthorized: false,
},
});