(request: Request)
| 2 | import { load } from "cheerio"; |
| 3 | |
| 4 | export async function GET(request: Request) { |
| 5 | try { |
| 6 | const { searchParams } = new URL(request.url); |
| 7 | const url = searchParams.get("url"); |
| 8 | |
| 9 | if (!url) { |
| 10 | return NextResponse.json({ error: "URL is required" }, { status: 400 }); |
| 11 | } |
| 12 | |
| 13 | // Validate and normalize URL |
| 14 | let validUrl: URL; |
| 15 | try { |
| 16 | validUrl = new URL(url); |
| 17 | // Add https if no protocol is specified |
| 18 | if (!validUrl.protocol || validUrl.protocol === ":") { |
| 19 | validUrl = new URL(`https://${url}`); |
| 20 | } |
| 21 | } catch (error) { |
| 22 | console.error("Invalid URL format:", error); |
| 23 | return NextResponse.json( |
| 24 | { error: "Invalid URL format" }, |
| 25 | { status: 400 }, |
| 26 | ); |
| 27 | } |
| 28 | |
| 29 | console.log("Fetching metadata for URL:", validUrl.toString()); |
| 30 | |
| 31 | const response = await fetch(validUrl.toString(), { |
| 32 | headers: { |
| 33 | "User-Agent": |
| 34 | "Mozilla/5.0 (compatible; DirectoryBot/1.0; +http://localhost)", |
| 35 | }, |
| 36 | }); |
| 37 | |
| 38 | if (!response.ok) { |
| 39 | return NextResponse.json( |
| 40 | { error: `Failed to fetch URL: ${response.statusText}` }, |
| 41 | { status: response.status }, |
| 42 | ); |
| 43 | } |
| 44 | |
| 45 | const html = await response.text(); |
| 46 | const $ = load(html); |
| 47 | |
| 48 | // Get favicon |
| 49 | let faviconUrl = |
| 50 | $('link[rel="icon"]').attr("href") || |
| 51 | $('link[rel="shortcut icon"]').attr("href") || |
| 52 | $('link[rel="apple-touch-icon"]').attr("href") || |
| 53 | "/favicon.ico"; // Default fallback |
| 54 | |
| 55 | // If favicon is relative, make it absolute |
| 56 | if (faviconUrl && !faviconUrl.startsWith("http")) { |
| 57 | try { |
| 58 | faviconUrl = new URL(faviconUrl, validUrl.origin).toString(); |
| 59 | } catch (e) { |
| 60 | console.warn("Failed to parse favicon URL:", e); |
| 61 | faviconUrl = "/favicon.ico"; |
nothing calls this directly
no outgoing calls
no test coverage detected