← back to build-pages
opensearch: /opensearch.xml descriptor + autodiscovery <link rel=search> in shell + 4 smoke
89a5046913336ddd8139eaa45205a04a883e0a21 · 2026-05-13 19:44:52 -0700 · SteveStudio2
Files touched
M server.jsM test/smoke.js
Diff
commit 89a5046913336ddd8139eaa45205a04a883e0a21
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 19:44:52 2026 -0700
opensearch: /opensearch.xml descriptor + autodiscovery <link rel=search> in shell + 4 smoke
---
server.js | 20 ++++++++++++++++++++
test/smoke.js | 8 ++++++++
2 files changed, 28 insertions(+)
diff --git a/server.js b/server.js
index 4b8341e..9abdca5 100644
--- a/server.js
+++ b/server.js
@@ -189,6 +189,7 @@ function shell(title, body, headExtra = '', meta = {}) {
<meta name="theme-color" content="#faf9f6" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#0d0c0a" media="(prefers-color-scheme: dark)">
<link rel="canonical" href="${esc(canonical)}">
+ <link rel="search" type="application/opensearchdescription+xml" title="build-pages" href="/opensearch.xml">
<meta property="og:title" content="${esc(title)}">
<meta property="og:description" content="${esc(desc)}">
<meta property="og:type" content="website">
@@ -1209,6 +1210,25 @@ app.get('/api/projects/:slug', async (req, res, next) => {
} catch (e) { next(e); }
});
+// /opensearch.xml — OpenSearch 1.1 description so browsers (Chrome, Firefox,
+// Safari Tech Preview) can register projects.agentabrams.com as a custom
+// search engine. Triggered by autodiscovery <link rel="search"> in the shell.
+app.get('/opensearch.xml', (_req, res) => {
+ const base = 'https://projects.agentabrams.com';
+ const xml = `<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+ <ShortName>build-pages</ShortName>
+ <Description>Search every commit across Steve Abrams' projects.</Description>
+ <InputEncoding>UTF-8</InputEncoding>
+ <Image height="32" width="32" type="image/svg+xml">${base}/favicon.svg</Image>
+ <Url type="text/html" method="get" template="${base}/?q={searchTerms}"/>
+ <Url type="application/json" method="get" template="${base}/api/search?q={searchTerms}&limit=50"/>
+</OpenSearchDescription>
+`;
+ res.setHeader('Cache-Control', 'public, max-age=86400');
+ res.type('application/opensearchdescription+xml').send(xml);
+});
+
// /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) => {
diff --git a/test/smoke.js b/test/smoke.js
index a62bc8f..a385334 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -220,6 +220,14 @@ function check(name, cond, hint = '') {
check('search: 302', r.status === 302);
check('search: redirects to /?q', /\/\?q=whisper/.test(r.headers['location'] || ''));
+ // 12c. OpenSearch — autodiscovery + descriptor
+ r = await fetch('/opensearch.xml');
+ check('opensearch: 200', r.status === 200);
+ check('opensearch: descriptor', /<OpenSearchDescription/.test(r.body));
+ check('opensearch: html url', /template=".+\/\?q=\{searchTerms\}/.test(r.body));
+ r = await fetch('/');
+ check('home: opensearch autodisc', /rel="search" type="application\/opensearchdescription\+xml"/.test(r.body));
+
// 13. branded 404 on unknown route
r = await fetch('/xyz-no-such-route');
check('404: status 404', r.status === 404);
← eff2d00 static pages: Cache-Control max-age=3600 SWR=86400 on /about
·
back to build-pages
·
favicon: /favicon.svg + /favicon.ico routes serve real brand 9419dd0 →