feat: add inline PDF viewer for Custom_PDF objects
Add a /pdf proxy route that forces Content-Disposition inline so PDFs render instead of downloading, and a web viewer that embeds the document in an iframe with a standalone open-in-new-tab link.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { Hono } from 'hono';
|
||||
import { GAMES_ROOT } from '../config.js';
|
||||
import { resolveAsset } from './resolveAsset.js';
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
/**
|
||||
* Fetch a PDF and stream it back inline so the browser renders it instead of
|
||||
* downloading. PDF hosts often send `Content-Disposition: attachment`, which
|
||||
* forces a download even when the URL is opened in a tab or iframe. This route
|
||||
* strips that header and forces `inline` so the PDF can be embedded in the web
|
||||
* app's viewer. Like `/asset`, a relative URL (no scheme) is treated as a game
|
||||
* asset path relative to `GAMES_ROOT`.
|
||||
*/
|
||||
app.get('/', async (c) => {
|
||||
const raw = c.req.query('url');
|
||||
if (!raw) {
|
||||
return c.json({ error: 'Missing url query param' }, 400);
|
||||
}
|
||||
|
||||
const result = await resolveAsset(raw, GAMES_ROOT);
|
||||
if (!result.ok) {
|
||||
return c.json(
|
||||
{ error: result.reason === 'not-found' ? 'Asset not found' : 'Invalid url query param' },
|
||||
result.reason === 'not-found' ? 404 : 400,
|
||||
);
|
||||
}
|
||||
const asset = result.asset;
|
||||
|
||||
// A local game asset is streamed from disk; a remote one is fetched.
|
||||
let body: BodyInit;
|
||||
if (asset.stream) {
|
||||
body = asset.stream as unknown as BodyInit;
|
||||
} else {
|
||||
let res: Response;
|
||||
try {
|
||||
res = await fetch(asset.url!);
|
||||
} catch (err) {
|
||||
return c.json({ error: `Failed to fetch pdf: ${String(err)}` }, 502);
|
||||
}
|
||||
if (!res.ok) {
|
||||
return c.json({ error: `Pdf responded ${res.status}` }, 502);
|
||||
}
|
||||
body = res.body!;
|
||||
}
|
||||
|
||||
return new Response(body, {
|
||||
headers: {
|
||||
'Content-Type': 'application/pdf',
|
||||
'Content-Disposition': 'inline',
|
||||
'Cache-Control': 'public, max-age=86400',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
export default app;
|
||||
Reference in New Issue
Block a user