import { Router } from 'express'; import axios from 'axios'; import * as cheerio from 'cheerio'; import { z } from 'zod'; const router = Router(); const previewSchema = z.object({ url: z.string().min(1) }); router.post('/meta-preview', async (req, res) => { try { let { url } = previewSchema.parse(req.body); // Add protocol if missing if (!url.startsWith('http://') && !url.startsWith('https://')) { url = `https://${url}`; } const response = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; WebsiteMonitorBot/1.0; +https://websitemonitor.com)' }, timeout: 5000, validateStatus: (status) => status < 500 // Resolve even if 404/403 to avoid crashing flow immediately }); const html = response.data; const $ = cheerio.load(html); const title = $('title').text() || $('meta[property="og:title"]').attr('content') || ''; const description = $('meta[name="description"]').attr('content') || $('meta[property="og:description"]').attr('content') || ''; // Attempt to find favicon let favicon = ''; const linkIcon = $('link[rel="icon"], link[rel="shortcut icon"], link[rel="apple-touch-icon"]').attr('href'); if (linkIcon) { if (linkIcon.startsWith('http')) { favicon = linkIcon; } else if (linkIcon.startsWith('//')) { favicon = `https:${linkIcon}`; } else { const urlObj = new URL(url); favicon = `${urlObj.protocol}//${urlObj.host}${linkIcon.startsWith('/') ? '' : '/'}${linkIcon}`; } } else { const urlObj = new URL(url); favicon = `${urlObj.protocol}//${urlObj.host}/favicon.ico`; } res.json({ title: title.trim(), description: description.trim(), favicon, url: url }); } catch (error) { console.error('Meta preview error:', error); if (error instanceof z.ZodError) { return res.status(400).json({ error: 'Invalid URL provided' }); } res.status(500).json({ error: 'Failed to fetch page metadata' }); } }); export const toolsRouter = router;