import { Hono } from 'hono'; const app = new Hono(); /** * Fetch an external asset (texture, model, etc.) and stream it back to the * client. Workshop asset hosts (steamusercontent.com, etc.) often omit CORS * headers, which would block `TextureLoader` / `GLTFLoader` in the browser. * Routing through the proxy makes those assets loadable. */ app.get('/', async (c) => { const raw = c.req.query('url'); if (!raw) { return c.json({ error: 'Missing url query param' }, 400); } let url: URL; try { url = new URL(raw); } catch { return c.json({ error: 'Invalid url query param' }, 400); } // Only allow http(s) to avoid SSRF via file://, etc. if (url.protocol !== 'http:' && url.protocol !== 'https:') { return c.json({ error: 'Only http(s) urls are allowed' }, 400); } let res: Response; try { res = await fetch(url); } catch (err) { return c.json({ error: `Failed to fetch asset: ${String(err)}` }, 502); } if (!res.ok) { return c.json({ error: `Asset responded ${res.status}` }, 502); } const contentType = res.headers.get('content-type') ?? 'application/octet-stream'; return new Response(res.body, { headers: { 'Content-Type': contentType, 'Cache-Control': 'public, max-age=86400', }, }); }); export default app;