feat(proxy): serve local game assets from games root

This commit is contained in:
2026-08-09 21:31:23 +08:00
parent 0503ac84a7
commit 91d4b6c999
7 changed files with 162 additions and 20 deletions
+21 -9
View File
@@ -4,6 +4,8 @@ import sharp from 'sharp';
import { createRequire } from 'module';
import { traceRequestSchema, type TraceResult } from '@tts/shared';
import { offsetShape, parseSvgShape } from './svgShape.js';
import { resolveAsset } from './resolveAsset.js';
import type { Bindings } from '../env.js';
// vtracer is a CommonJS package; load it via require so the wasm initializes
// with the correct `__dirname`.
@@ -17,7 +19,7 @@ const vtracer = require('@visioncortex/vtracer') as {
): string;
};
const app = new Hono();
const app = new Hono<{ Bindings: Bindings }>();
/**
* Trace an image into a vector shape and return it BSON-encoded.
@@ -39,19 +41,29 @@ app.get('/', async (c) => {
const { url, mode, threshold, format, simplify, maxColors, offset } =
parsed.data;
// Only allow http(s) to avoid SSRF via file://, etc.
const parsedUrl = new URL(url);
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
return c.json({ error: 'Only http(s) urls are allowed' }, 400);
// Resolve the image: a relative path is a local game asset under GAMES_ROOT;
// otherwise it must be an http(s) URL.
const resolved = await resolveAsset(url, c.env?.GAMES_ROOT);
if (!resolved.ok) {
return c.json({ error: 'Invalid or missing image url' }, 400);
}
const asset = resolved.asset;
let image: Buffer;
try {
const res = await fetch(url);
if (!res.ok) {
return c.json({ error: `Image responded ${res.status}` }, 502);
if (asset.stream) {
const chunks: Buffer[] = [];
for await (const chunk of asset.stream) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
image = Buffer.concat(chunks);
} else {
const res = await fetch(asset.url!);
if (!res.ok) {
return c.json({ error: `Image responded ${res.status}` }, 502);
}
image = Buffer.from(await res.arrayBuffer());
}
image = Buffer.from(await res.arrayBuffer());
} catch (err) {
return c.json({ error: `Failed to fetch image: ${String(err)}` }, 502);
}