diff --git a/server/public/home.html b/server/public/home.html
index 990bf4a..0ce3820 100644
--- a/server/public/home.html
+++ b/server/public/home.html
@@ -589,7 +589,7 @@
-
+
Loading…
diff --git a/server/static.js b/server/static.js
index b2954f2..633d56f 100644
--- a/server/static.js
+++ b/server/static.js
@@ -23,15 +23,22 @@ function serveStatic(req, res) {
// tiny 304 (no re-download) when nothing changed — fast reloads, but always fresh on edits.
fs.stat(fp, (serr, st) => {
if (serr || !st.isFile()) return json(res, 404, { error: 'not found' });
- const ct = MIME[path.extname(fp)] || 'application/octet-stream';
+ const ext = path.extname(fp);
+ const ct = MIME[ext] || 'application/octet-stream';
+ // HTML entry pages are NEVER cached (no-store) so a deploy reaches every browser on the
+ // next load — no hard-refresh needed. Versioned assets (e.g. icons.js?v=) still revalidate
+ // cheaply via ETag/304.
+ const isHtml = ext === '.html';
const etag = '"' + st.size.toString(16) + '-' + Math.round(st.mtimeMs).toString(16) + '"';
- if (req.headers['if-none-match'] === etag) {
+ if (!isHtml && req.headers['if-none-match'] === etag) {
res.writeHead(304, { ETag: etag, 'Cache-Control': 'no-cache' });
return res.end();
}
fs.readFile(fp, (err, data) => {
if (err) return json(res, 404, { error: 'not found' });
- res.writeHead(200, { 'Content-Type': ct, 'Cache-Control': 'no-cache', ETag: etag, 'Content-Length': st.size });
+ const headers = { 'Content-Type': ct, 'Content-Length': st.size, 'Cache-Control': isHtml ? 'no-store, must-revalidate' : 'no-cache' };
+ if (!isHtml) headers.ETag = etag;
+ res.writeHead(200, headers);
res.end(data);
});
});