← back to build-pages
alias: /search?q= 302→/?q= (convention path) + 2 smoke
451c6ade4a2f0254f9fba1a1ef7889036593821d · 2026-05-13 19:36:36 -0700 · SteveStudio2
Files touched
M server.jsM test/smoke.js
Diff
commit 451c6ade4a2f0254f9fba1a1ef7889036593821d
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 19:36:36 2026 -0700
alias: /search?q= 302→/?q= (convention path) + 2 smoke
---
server.js | 7 +++++++
test/smoke.js | 5 +++++
2 files changed, 12 insertions(+)
diff --git a/server.js b/server.js
index 671eac9..3245d14 100644
--- a/server.js
+++ b/server.js
@@ -1209,6 +1209,13 @@ app.get('/api/projects/:slug', async (req, res, next) => {
} catch (e) { next(e); }
});
+// /search — convention alias that 302s to home with ?q= prefilled. Lets folks
+// who guess "/search" land on the right surface.
+app.get('/search', (req, res) => {
+ const q = typeof req.query.q === 'string' ? req.query.q : '';
+ res.redirect(302, q ? `/?q=${encodeURIComponent(q)}` : '/');
+});
+
// /privacy — what data this site collects. The honest answer: very little.
app.get('/privacy', (_req, res) => {
res.send(shell('Privacy — build-pages', `
diff --git a/test/smoke.js b/test/smoke.js
index 4b66ee2..a6a414c 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -214,6 +214,11 @@ function check(name, cond, hint = '') {
check('commits api: 3 returned', /"limit":3/.test(r.body));
check('commits api: hash field', /"hash":"[a-f0-9]{4,}/.test(r.body));
+ // 12b. /search alias → /?q=
+ r = await fetch('/search?q=whisper', { method: 'GET' });
+ check('search: 302', r.status === 302);
+ check('search: redirects to /?q', /\/\?q=whisper/.test(r.headers['location'] || ''));
+
// 13. branded 404 on unknown route
r = await fetch('/xyz-no-such-route');
check('404: status 404', r.status === 404);
← 3af9a44 ui: /privacy + /terms boilerplate (no-tracking + as-is) — si
·
back to build-pages
·
static pages: Cache-Control max-age=3600 SWR=86400 on /about eff2d00 →