106 lines
4.1 KiB
TypeScript
106 lines
4.1 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server"
|
|
import { optimizeImage } from "./image-optimizer"
|
|
import { getToken } from "next-auth/jwt"
|
|
|
|
const API_URL = (process.env.NEXT_PUBLIC_API_URL || "http://localhost:8080") + "/api/v1"
|
|
|
|
export async function handleImageProxyRequest(req: NextRequest, targetEndpoint: string) {
|
|
try {
|
|
const formData = await req.formData()
|
|
const newFormData = new FormData()
|
|
|
|
// Process fields
|
|
// We need to iterate twice: first to collect all config fields, then to process files
|
|
const configMap = new Map<string, string>()
|
|
for (const [key, value] of formData.entries()) {
|
|
if (typeof value === "string") {
|
|
configMap.set(key, value)
|
|
}
|
|
}
|
|
|
|
for (const [key, value] of formData.entries()) {
|
|
if (value instanceof File && value.size > 0) {
|
|
// Determine configuration for this file
|
|
let width = 0
|
|
let height = 0
|
|
let quality = 80
|
|
let format = "avif"
|
|
|
|
// Heuristic 1: "image" field maps to root "width", "height", etc.
|
|
if (key === "image") {
|
|
width = Number(configMap.get("width")) || 0
|
|
height = Number(configMap.get("height")) || 0
|
|
quality = Number(configMap.get("quality")) || 80
|
|
format = configMap.get("format") || "avif"
|
|
}
|
|
// Heuristic 2: "[prefix]_logo" maps to "[prefix]_width", etc.
|
|
else if (key.endsWith("_logo")) {
|
|
const prefix = key.replace("_logo", "")
|
|
width = Number(configMap.get(`${prefix}_width`)) || 0
|
|
height = Number(configMap.get(`${prefix}_height`)) || 0
|
|
quality = Number(configMap.get(`${prefix}_quality`)) || 80
|
|
format = configMap.get(`${prefix}_format`) || "avif"
|
|
}
|
|
|
|
// If any config is found (or defaults for "image"), optimize
|
|
if (key === "image" || key.endsWith("_logo")) {
|
|
const buffer = Buffer.from(await value.arrayBuffer())
|
|
const { buffer: processedBuffer, contentType, filename } = await optimizeImage(buffer, {
|
|
width,
|
|
height,
|
|
quality,
|
|
format,
|
|
})
|
|
|
|
// Create Blob from Buffer
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const blob = new Blob([processedBuffer as any], { type: contentType })
|
|
newFormData.append(key, blob, filename)
|
|
} else {
|
|
// Just forward other files as is
|
|
newFormData.append(key, value)
|
|
}
|
|
} else {
|
|
newFormData.append(key, value)
|
|
}
|
|
}
|
|
|
|
// Get Auth Token (Server-side)
|
|
// NextAuth's getSession might not work in API routes depending on setup,
|
|
// getToken is more reliable for middleware/API routes.
|
|
const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET })
|
|
|
|
const headers: HeadersInit = {}
|
|
if (token && token.accessToken) {
|
|
headers["Authorization"] = `Bearer ${token.accessToken}`
|
|
}
|
|
|
|
// Determine method (POST or PUT)
|
|
const method = req.method
|
|
|
|
const targetUrl = `${API_URL}${targetEndpoint}`
|
|
|
|
const response = await fetch(targetUrl, {
|
|
method: method,
|
|
headers: headers,
|
|
body: newFormData,
|
|
})
|
|
|
|
const data = await response.json()
|
|
|
|
if (!response.ok) {
|
|
return NextResponse.json(data, { status: response.status })
|
|
}
|
|
|
|
return NextResponse.json(data)
|
|
|
|
} catch (error: unknown) {
|
|
console.error("Proxy Error:", error)
|
|
const errorMessage = error instanceof Error ? error.message : "Internal Server Error"
|
|
return NextResponse.json(
|
|
{ error: errorMessage },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|