fix: privacy 404 + enhanced playground controls
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 9m7s

BUG-010: Add 301 redirects for clean URLs (/privacy → /privacy.html etc.)
and fix inconsistent href links across legal pages.

FEATURE: Enhanced playground with fullPage, quality, deviceScale,
waitUntil, and waitForSelector controls for better API evaluation.
This commit is contained in:
SnapAPI Agent 2026-02-22 08:52:32 +00:00
parent d20fbbfe2e
commit db1fa8d506
6 changed files with 79 additions and 22 deletions

View file

@ -122,6 +122,11 @@ app.get("/openapi.json", (_req, res) => {
app.get("/docs", (_req, res) => {
res.sendFile(path.join(__dirname, "../public/docs.html"));
});
// Clean URLs for legal pages (redirect /privacy → /privacy.html, etc.)
for (const page of ["privacy", "terms", "impressum", "status"]) {
app.get(`/${page}`, (_req, res) => res.redirect(301, `/${page}.html`));
}
// Static files (landing page)
app.use(express.static(path.join(__dirname, "../public"), { etag: true }));

View file

@ -84,7 +84,7 @@ const playgroundLimiter = rateLimit({
* schema: { $ref: "#/components/schemas/Error" }
*/
playgroundRouter.post("/", playgroundLimiter, async (req, res) => {
const { url, format, width, height } = req.body;
const { url, format, width, height, fullPage, quality, waitForSelector, deviceScale, waitUntil } = req.body;
if (!url || typeof url !== "string") {
res.status(400).json({ error: "Missing required parameter: url" });
@ -95,6 +95,14 @@ playgroundRouter.post("/", playgroundLimiter, async (req, res) => {
const safeWidth = Math.min(Math.max(parseInt(width, 10) || 1280, 320), 1920);
const safeHeight = Math.min(Math.max(parseInt(height, 10) || 800, 200), 1080);
const safeFormat = ["png", "jpeg", "webp"].includes(format) ? format : "png";
const safeFullPage = fullPage === true;
const safeQuality = safeFormat === "png" ? undefined : Math.min(Math.max(parseInt(quality, 10) || 80, 1), 100);
const safeDeviceScale = Math.min(Math.max(parseInt(deviceScale, 10) || 1, 1), 3);
const validWaitUntil = ["load", "domcontentloaded", "networkidle0", "networkidle2"];
const safeWaitUntil = validWaitUntil.includes(waitUntil) ? waitUntil : "domcontentloaded";
// Sanitize waitForSelector — allow simple CSS selectors only (no script injection)
const safeWaitForSelector = typeof waitForSelector === "string" && /^[a-zA-Z0-9\s\-_.#\[\]=:"'>,+~()]+$/.test(waitForSelector) && waitForSelector.length <= 200
? waitForSelector : undefined;
try {
const result = await takeScreenshot({
@ -102,9 +110,11 @@ playgroundRouter.post("/", playgroundLimiter, async (req, res) => {
format: safeFormat as "png" | "jpeg" | "webp",
width: safeWidth,
height: safeHeight,
fullPage: false,
quality: safeFormat === "png" ? undefined : 70,
deviceScale: 1,
fullPage: safeFullPage,
quality: safeQuality,
deviceScale: safeDeviceScale,
waitUntil: safeWaitUntil as any,
waitForSelector: safeWaitForSelector,
});
// Add watermark