style: format code for better readability

- Format arrays and objects on multiple lines for clarity
- Add trailing commas to arrays and objects
- Format function parameters across multiple lines when needed
- Format string concatenation and template literals consistently
- Format try-catch blocks with proper spacing
This commit is contained in:
2026-05-13 13:46:47 +02:00
parent ac759a60fe
commit 5020d2c288
+151 -47
View File
@@ -164,8 +164,8 @@ if (viewCount === 0) {
"Demo View",
JSON.stringify([
{ url: "https://www.google.com", durationSec: 30, forceDarkMode: false, bakeStyles: false },
{ url: "https://duck.ai", durationSec: 30, forceDarkMode: false, bakeStyles: false },
{ url: "https://www.msn.com", durationSec: 30, forceDarkMode: false, bakeStyles: false },
{ url: "https://duck.ai", durationSec: 30, forceDarkMode: false, bakeStyles: false },
{ url: "https://www.msn.com", durationSec: 30, forceDarkMode: false, bakeStyles: false },
]),
"ssr",
0,
@@ -229,7 +229,7 @@ function dbDelete(id: string): boolean {
function dbBanIP(ip: string, reason?: string): void {
db.run(
"INSERT OR REPLACE INTO banned_ips (ip, banned_at, reason, banned_by) VALUES (?, ?, ?, ?)",
[ip, Math.floor(Date.now() / 1000), reason ?? "Manual ban", "admin"]
[ip, Math.floor(Date.now() / 1000), reason ?? "Manual ban", "admin"],
);
}
@@ -241,7 +241,12 @@ function dbIsBanned(ip: string): boolean {
return db.query("SELECT ip FROM banned_ips WHERE ip = ?").get(ip) != null;
}
function dbGetBannedIPs(): Array<{ ip: string; banned_at: number; reason: string; banned_by: string }> {
function dbGetBannedIPs(): Array<{
ip: string;
banned_at: number;
reason: string;
banned_by: string;
}> {
return db.query("SELECT * FROM banned_ips ORDER BY banned_at DESC").all() as Array<{
ip: string;
banned_at: number;
@@ -292,11 +297,11 @@ function deviceTrack(ip: string, viewId: string, viewName: string, userAgent: st
existing.requestCount++;
} else {
devices.set(ip, { ip, viewId, viewName, userAgent, lastSeen: Date.now(), requestCount: 1 });
// First user connecting to this view - trigger warmup
if (!warmedUpViews.has(viewId)) {
warmedUpViews.add(viewId);
warmupView(viewId).catch(err => {
warmupView(viewId).catch((err) => {
console.error(`[warmup] Failed to warm up view ${viewId}:`, err);
});
}
@@ -321,7 +326,7 @@ function devicesSnapshot(): DeviceEntry[] {
// ═══════════════════════════════════════════════════════════════
function getDebugData() {
const viewsDebug = viewCacheAll().map(v => {
const viewsDebug = viewCacheAll().map((v) => {
const idx = getCurrentURLIndex(v);
return {
id: v.id,
@@ -336,7 +341,7 @@ function getDebugData() {
currentUrl: v.urls[idx]?.url ?? "",
remainingSec: getRemainingSec(v),
totalCycleSec: v.urls.reduce((s, u) => s + u.durationSec, 0),
cacheEntries: cacheStats().filter(c => c.viewId === v.id),
cacheEntries: cacheStats().filter((c) => c.viewId === v.id),
};
});
@@ -438,7 +443,9 @@ class PagePool {
return true;
} catch (err) {
console.warn(`[page-pool] resetPage failed, discarding page: ${err}`);
try { await page.close(); } catch {}
try {
await page.close();
} catch {}
return false;
}
}
@@ -513,10 +520,7 @@ let pagePool: PagePool;
// WEBSOCKET DEBUG CLIENTS
// ═══════════════════════════════════════════════════════════════
const debugClients = new Map<
any,
{ interval: number; timer: ReturnType<typeof setInterval> }
>();
const debugClients = new Map<any, { interval: number; timer: ReturnType<typeof setInterval> }>();
const DEBUG_DEFAULT_INTERVAL_MS = 1000;
const DEBUG_MIN_INTERVAL_MS = 100;
@@ -668,12 +672,19 @@ async function renderViewToCache(view: View, urlIndex: number, key: string): Pro
let body: string;
if (view.method === "mjpeg") {
const jpeg = await renderScreenshotFrame(
urlItem.url, view.viewportWidth, view.viewportHeight, forceDarkMode,
urlItem.url,
view.viewportWidth,
view.viewportHeight,
forceDarkMode,
);
body = jpeg.toString("base64");
} else {
body = await renderSSR(
urlItem.url, view.viewportWidth, view.viewportHeight, forceDarkMode, bakeStyles,
urlItem.url,
view.viewportWidth,
view.viewportHeight,
forceDarkMode,
bakeStyles,
);
}
@@ -823,7 +834,8 @@ function stripScriptTags(html: string): string {
// ── Recursive @import resolver (max 3 levels deep) ──
async function resolveCSSImports(cssText: string, baseUrl: string, depth = 0): Promise<string> {
if (depth > 3) return cssText;
const importRe = /@import\s+(?:url\s*\(\s*["']?([^)"']+)["']?\s*\)|["']([^"']+)["'])\s*([^;]*);/gi;
const importRe =
/@import\s+(?:url\s*\(\s*["']?([^)"']+)["']?\s*\)|["']([^"']+)["'])\s*([^;]*);/gi;
const replacements: Array<{ match: string; resolved: string }> = [];
let m: RegExpExecArray | null;
@@ -839,7 +851,10 @@ async function resolveCSSImports(cssText: string, baseUrl: string, depth = 0): P
if (!res.ok) throw new Error("failed");
let imported = await res.text();
imported = await resolveCSSImports(imported, importUrl, depth + 1);
replacements.push({ match: m[0], resolved: "/* begin " + importUrl + " */\n" + imported + "\n/* end " + importUrl + " */" });
replacements.push({
match: m[0],
resolved: "/* begin " + importUrl + " */\n" + imported + "\n/* end " + importUrl + " */",
});
} catch {
replacements.push({ match: m[0], resolved: "/* unresolved import: " + importUrl + " */" });
}
@@ -865,40 +880,117 @@ async function bakeComputedStyles(page: Page): Promise<void> {
await page.evaluate((): void => {
const computedProperties = [
// Layout
"display", "position", "top", "right", "bottom", "left",
"width", "height", "min-width", "min-height", "max-width", "max-height",
"margin", "margin-top", "margin-right", "margin-bottom", "margin-left",
"padding", "padding-top", "padding-right", "padding-bottom", "padding-left",
"display",
"position",
"top",
"right",
"bottom",
"left",
"width",
"height",
"min-width",
"min-height",
"max-width",
"max-height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
// Flex/Grid
"flex", "flex-direction", "flex-wrap", "flex-flow", "flex-grow", "flex-shrink", "flex-basis",
"justify-content", "align-items", "align-content", "align-self", "gap", "row-gap", "column-gap",
"grid", "grid-template", "grid-template-columns", "grid-template-rows", "grid-area",
"flex",
"flex-direction",
"flex-wrap",
"flex-flow",
"flex-grow",
"flex-shrink",
"flex-basis",
"justify-content",
"align-items",
"align-content",
"align-self",
"gap",
"row-gap",
"column-gap",
"grid",
"grid-template",
"grid-template-columns",
"grid-template-rows",
"grid-area",
// Box model
"box-sizing", "border-top-width", "border-right-width", "border-bottom-width", "border-left-width",
"border-top-style", "border-right-style", "border-bottom-style", "border-left-style",
"border-top-color", "border-right-color", "border-bottom-color", "border-left-color",
"border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius",
"box-sizing",
"border-top-width",
"border-right-width",
"border-bottom-width",
"border-left-width",
"border-top-style",
"border-right-style",
"border-bottom-style",
"border-left-style",
"border-top-color",
"border-right-color",
"border-bottom-color",
"border-left-color",
"border-top-left-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
// Colors & Background
"color", "background-color", "background-image", "background-size", "background-position",
"background-repeat", "background-attachment", "background-clip", "background-origin",
"color",
"background-color",
"background-image",
"background-size",
"background-position",
"background-repeat",
"background-attachment",
"background-clip",
"background-origin",
// Typography
"font-family", "font-size", "font-weight", "font-style", "font-variant",
"line-height", "text-align", "text-decoration-line", "text-decoration-color",
"text-transform", "letter-spacing", "word-spacing",
"white-space", "overflow-wrap", "word-break",
"font-family",
"font-size",
"font-weight",
"font-style",
"font-variant",
"line-height",
"text-align",
"text-decoration-line",
"text-decoration-color",
"text-transform",
"letter-spacing",
"word-spacing",
"white-space",
"overflow-wrap",
"word-break",
// Visual
"opacity", "visibility", "z-index", "overflow-x", "overflow-y",
"box-shadow", "text-shadow", "transform", "transform-origin",
"opacity",
"visibility",
"z-index",
"overflow-x",
"overflow-y",
"box-shadow",
"text-shadow",
"transform",
"transform-origin",
// List/Table
"list-style-type", "list-style-position", "border-collapse", "border-spacing",
"list-style-type",
"list-style-position",
"border-collapse",
"border-spacing",
// Cursor/pointer
"cursor", "pointer-events",
"cursor",
"pointer-events",
];
// Cache of default computed values keyed by tagName
const defaultCache = new Map<string, Map<string, string>>();
const hiddenContainer = document.createElement("div");
hiddenContainer.style.cssText = "position:absolute;visibility:hidden;pointer-events:none;top:-9999px;";
hiddenContainer.style.cssText =
"position:absolute;visibility:hidden;pointer-events:none;top:-9999px;";
document.body.appendChild(hiddenContainer);
function getTagDefaults(tag: string): Map<string, string> {
@@ -913,7 +1005,9 @@ async function bakeComputedStyles(page: Page): Promise<void> {
cache.set(prop, cs.getPropertyValue(prop));
}
el.remove();
} catch { /* unknown tag, cache will be empty */ }
} catch {
/* unknown tag, cache will be empty */
}
defaultCache.set(tag, cache);
return cache;
}
@@ -921,7 +1015,8 @@ async function bakeComputedStyles(page: Page): Promise<void> {
function shouldBake(value: string, defaultValue: string): boolean {
if (!value) return false;
// Skip browser keywords that cannot be serialized as inline style values
if (value === "initial" || value === "inherit" || value === "unset" || value === "revert") return false;
if (value === "initial" || value === "inherit" || value === "unset" || value === "revert")
return false;
return value !== defaultValue;
}
@@ -931,7 +1026,8 @@ async function bakeComputedStyles(page: Page): Promise<void> {
if (el === hiddenContainer) continue;
// Skip non-visual tags
const tag = el.tagName.toLowerCase();
if (["script", "style", "meta", "link", "noscript", "template", "head", "html"].includes(tag)) continue;
if (["script", "style", "meta", "link", "noscript", "template", "head", "html"].includes(tag))
continue;
const computed = window.getComputedStyle(el);
const defaults = getTagDefaults(tag);
@@ -1081,7 +1177,7 @@ async function inlineAllResources(page: Page, html: string): Promise<string> {
html = html.replace(
linkRegex,
`<style${mediaAttr}>/* inlined: ${css.url} */\n${resolvedCSS}\n</style>`
`<style${mediaAttr}>/* inlined: ${css.url} */\n${resolvedCSS}\n</style>`,
);
}
for (const img of payload.images) {
@@ -1498,7 +1594,9 @@ const server = Bun.serve<{ interval: number }>({
}, interval);
debugClients.set(ws, { interval, timer });
// Send initial payload immediately
try { ws.send(JSON.stringify(getDebugData())); } catch {}
try {
ws.send(JSON.stringify(getDebugData()));
} catch {}
},
message(ws, msg) {
try {
@@ -1510,15 +1608,21 @@ const server = Bun.serve<{ interval: number }>({
clearInterval(client.timer);
client.interval = interval;
client.timer = setInterval(() => {
try { ws.send(JSON.stringify(getDebugData())); } catch {
try {
ws.send(JSON.stringify(getDebugData()));
} catch {
clearInterval(client.timer);
debugClients.delete(ws);
}
}, interval);
// Push immediately after rate change
try { ws.send(JSON.stringify(getDebugData())); } catch {}
try {
ws.send(JSON.stringify(getDebugData()));
} catch {}
}
} catch { /* ignore malformed messages */ }
} catch {
/* ignore malformed messages */
}
},
close(ws) {
const client = debugClients.get(ws);