[object Object]

← back to Cronjobs Viewer

5x sweep 2: fix intermittent favicon.ico 404 console error (server route + <link rel=icon>)

f4729fe52ae4c5acade8a69010389b98869497e1 · 2026-08-25 11:28:53 -0700 · steve

Files touched

Diff

commit f4729fe52ae4c5acade8a69010389b98869497e1
Author: steve <steve@designerwallcoverings.com>
Date:   Tue Aug 25 11:28:53 2026 -0700

    5x sweep 2: fix intermittent favicon.ico 404 console error (server route + <link rel=icon>)
---
 5x/capture-404.js     | 13 +++++++++++++
 5x/capture-console.js | 19 +++++++++++++++++++
 public/index.html     |  1 +
 server.js             |  8 ++++++++
 4 files changed, 41 insertions(+)

diff --git a/5x/capture-404.js b/5x/capture-404.js
new file mode 100644
index 0000000..c173e4a
--- /dev/null
+++ b/5x/capture-404.js
@@ -0,0 +1,13 @@
+const pw = require('/Users/macstudio3/.npm-global/lib/node_modules/playwright');
+const CHROME = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+(async () => {
+  const b = await pw.chromium.launch({ executablePath: CHROME });
+  const ctx = await b.newContext({ httpCredentials:{username:'admin',password:'DW2024!'}});
+  const p = await ctx.newPage();
+  const bad = [];
+  p.on('response', r => { if (r.status() >= 400) bad.push(`${r.status()}  ${r.url()}`); });
+  await p.goto('http://127.0.0.1:9772/', { waitUntil:'networkidle', timeout:20000 });
+  await p.waitForTimeout(1500);
+  await b.close();
+  console.log(bad.length ? bad.join('\n') : 'NO 4xx/5xx');
+})();
diff --git a/5x/capture-console.js b/5x/capture-console.js
new file mode 100644
index 0000000..01680de
--- /dev/null
+++ b/5x/capture-console.js
@@ -0,0 +1,19 @@
+const pw = require('/Users/macstudio3/.npm-global/lib/node_modules/playwright');
+const CHROME = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+(async () => {
+  const b = await pw.chromium.launch({ executablePath: CHROME });
+  const seen = [];
+  for (let i = 0; i < 8; i++) {
+    const ctx = await b.newContext({ httpCredentials: { username:'admin', password:'DW2024!' }});
+    const p = await ctx.newPage();
+    const local = [];
+    p.on('console', m => { if (m.type() === 'error') local.push('CONSOLE: ' + m.text()); });
+    p.on('pageerror', e => local.push('PAGEERROR: ' + e.message));
+    await p.goto('http://127.0.0.1:9772/', { waitUntil:'networkidle', timeout:20000 }).catch(e=>local.push('GOTO: '+e.message));
+    await p.waitForTimeout(1200);
+    if (local.length) seen.push(`load#${i}: ` + local.join(' || '));
+    await ctx.close();
+  }
+  await b.close();
+  console.log(seen.length ? seen.join('\n') : 'NO ERRORS across 8 loads');
+})();
diff --git a/public/index.html b/public/index.html
index 6ecc949..8efe14d 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,6 +1,7 @@
 <!doctype html>
 <html lang="en">
 <head>
+<link rel="icon" href="/favicon.ico">
 <script>
 // Credential-safe fetch guard (fleet drop-in) — if this page is opened with
 // credentials in the URL (a saved bookmark / Chrome-remembered basic-auth:
diff --git a/server.js b/server.js
index 928203d..79bce7b 100644
--- a/server.js
+++ b/server.js
@@ -171,6 +171,14 @@ app.get('/api/crons', async (req, res) => {
 });
 
 app.get('/healthz', (req, res) => res.json({ ok: true }));
+// Favicon: browsers auto-request /favicon.ico with no HTML reference; without this
+// route express.static 404s it → a (cached, intermittent) console error. Serve a tiny
+// inline SVG clock so any client — including a direct bookmark hit — gets a 200.
+app.get('/favicon.ico', (_req, res) => {
+  res.type('image/svg+xml').set('Cache-Control', 'public, max-age=86400').send(
+    "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><text y='13' font-size='13'>🕓</text></svg>"
+  );
+});
 app.use(express.static(path.join(__dirname, 'public')));
 
 app.listen(PORT, () => console.log(`cronjobs-viewer on http://127.0.0.1:${PORT} (Basic ${AUTH_USER}/****)`));

← aa15665 creds-safe fetch guard: resolve relative fetch vs credential  ·  back to Cronjobs Viewer  ·  5x: REPORT + capture harness (2 clean sweeps, favicon 404 fi 62c68e7 →